LoginSignup
2
2

More than 5 years have passed since last update.

Robolectricの@Configを共通化する方法

Last updated at Posted at 2016-06-11

Robolectricの@Configアノテーションで指定する各種設定を
共通化させる方法を紹介します。

(この内容はAndroid Testing Bootcamp #2で、発表した内容と同じですが、
そこで説明しきれなかった補足も付け加えています。)

前提条件

この記事は、Robolectric3.1を使用した際の説明となっています。
ただしRobolectric3.0でも、少しコードを修正すれば適用できる内容となります。
このサンプルプロジェクトで、3.1と3.0それぞれに対応したコードを載せています。

一般的なRobolectricの使い方

一般的なRobolectircの使い方は以下のとおりだと思います。

  1. @RunWithRobolectricGradleTestRunnerを指定
  2. @Configに必要な各種設定を指定
ExampleUnitTest.java
@RunWith(RobolectricGradleTestRunner.class)
@Config(
  sdk = 23,
  constants = BuildConfig.class
)
public class ExampleUnitTest {

  @Test public void addition_isCorrect() throws Exception {
    assertEquals(4, 2 + 2);
  }

}

問題点

ただし上記のような、テストクラスで@Configの各設定を指定するという、一般的な方法を用いると
以下の様な問題が後々起こる可能性が出てきます。

  1. テストクラスを作成するたびに@Configを指定しなくてはならず面倒
  2. 指定したすべての@Configの設定を一括で変更したい場合、

    すべてのテストクラスを修正しなくてはいけない
  3. Robolectricがバージョンアップし、その結果@Configの設定方法が変更になった場合、
    すべてのテストクラスを修正しなくてはいけない

以上の問題から、@Configの設定を共通化できるものは、できるだけしておきたいです。

共通化する2つの方法

以上を踏まえ、@Configの設定を共通化する方法を、2つ紹介します。

その1 - ファイルに切り出す

この方法は、公式で提供している機能を使います。
image

やり方としては、以下のとおりです。
1. robolectric.propertiesというファイルを作る
2. このファイルに、共通化させたい@Configの設定を記述する
3. このファイルを、app/src/test/resourcesディレクトリに置く

app/src/test/resources/robolectric.properties
sdk=23

constants=my.package.BuildConfig

結果

このテストランナーを用いたテストコードは以下になります。
これにより、@Configアノテーションを指定せずに、共通化したい@Configの設定を指定できます。

ExampleUnitTest.java
@RunWith(RobolectricGradleTestRunner.class)
public class ExampleUnitTest {

  @Test public void addition_isCorrect() throws Exception {
    assertEquals(4, 2 + 2);
  }

}

その2 - テストランナーを作成する

この方法では、@Configの設定を共通化できるテストランナーを作ります。

RobolectricCustomRunner.java
public class RobolectricCustomRunner extends RobolectricGradleTestRunner {
  private static final int[] SDK = new int[]{23};

  public RobolectricCustomRunner(Class<?> klass) throws InitializationError {
    super(klass);
  }

  @Override public Config getConfig(Method method) {
    // 実際のテストクラスで指定、生成されたConfigを取得
    Config c = super.getConfig(method);

    // Configの設定を書き換えたものを登録する
    return new Config.Implementation(
        sdkLevel,
        c.manifest(), c.qualifiers(), c.packageName(),
        c.abiSplit(), c.resourceDir(), c.assetDir(),
        c.buildDir(), c.shadows(), c.instrumentedPackages(),
        c.application(), c.libraries(),
        constants
    );
  }

  // Config#sdkを指定していなかった場合は23に
  private static int[] pickSdkLevel(int[] sdkArray) {
    return sdkArray.length == 0 ? SDK : sdkArray;
  }

  private static Class<?> pickConstants(Class<?> constants) {
    return constants == Void.class ? BuildConfig.class : constants;
  }

}

結果

このテストランナーを用いたテストコードは以下になります。
これにより、@Configアノテーションを指定せずに、共通化したい@Configの設定を指定できます。

ExampleUnitTest.java
@RunWith(RobolectricCustomRunner.class)
public class ExampleUnitTest {

  @Test public void addition_isCorrect() throws Exception {
    assertEquals(4, 2 + 2);
  }

}

どちらの方法を採用するべきか

これは私個人の意見となりますが、以下の理由により、
テストランナーを用いた方法を採用したほうがいいと考えています。

  1. コードで設定を記述できるので、柔軟に指定できる。
    (例えば各BuildVariantで違う設定をする)
  2. 今後テストランナーを使ってRobolectricのカスタマイズをする必要が出てきた時、
    その設定と@Configの設定を一元管理できる
  3. ファイル、テストランナー、どちらの方法でもテストクラス作成時のコード量は変わらない。
    (どちらも@RunWithでテストランナーを指定する)

補足

テストクラスに@Configを絶対に書かないほうが良いというわけではなく、
Robolectricを使うテストクラスで常に指定する@Configの設定を出来る限り共通化したほうがいいのではないかというのが、
この記事の伝えたいことになります。

資料

参考

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2