日々精進

新しく学んだことを書き留めていきます

Robolectricでテスト実行開始時に一度だけ処理を実行させる

Robolectricで単体テスト実行中にBuild.VERSION.RELEASEからOSのバージョンを取得すると、"unknown"が返ってくる。
これでは都合が悪いので、テスト実行開始時にBuild.VERSION.RELEASEを書き換えてやろうと思ったのが事の発端。これが結構大変だった。。
やり方は以下。

  • カスタムTestRunerを定義し、それを使用するようにする。
    つまり、テストクラスに@RunWith(MyTestRunner.class)を付ける
  • カスタムTestRunnerは以下のように実装する。

public class MyTestRunner extends RobolectricTestRunner {
    public MyTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected Class<? extends TestLifecycle> getTestLifecycleClass() {
        return MyTestLifecycle.class;
    }

    public static class MyTestLifecycle extends DefaultTestLifecycle {
        private static boolean setUpIsDone = false;

        public MyTestLifecycle() throws Exception {
            super();
            if (!setUpIsDone) {
                // この処理を呼ぶタイミングとしては一見beforeTestの方が適切に見えるが、
                // beforeTestメソッドが呼ばれる前にBuild.VERSION.RELEASE等にShadowSystemPropertiesから
                // 取得した文字列がセットされるためbeforeTestでは遅い。そのためここで呼んでいる。
                setUpBeforeTestCasesOnlyOnce();
                setUpIsDone = true;
            }
        }

        /** テスト実行前に一度だけ実行する処理(テストケース毎に一度ではなく、テスト実行毎に一度実行する) */
        private void setUpBeforeTestCasesOnlyOnce() throws Exception {
            ShadowLog.stream = System.out;

            // OSのバージョン、端末のモデル番号をShadowSystemPropertiesから取得できるようにする
            Field field = ShadowSystemProperties.class.getDeclaredField("VALUES");
            field.setAccessible(true);
            Map<String, Object> values = (Map<String, Object>) field.get(null);
            values.put("ro.build.version.release", "5.0.0");
            values.put("ro.product.model", "Nexus 7");

            MyUtils.logMethodCall(this);
        }
    }
}

setUpBeforeTestCasesOnlyOnceに相当するメソッドってTestLifecycleに用意されてないのかな。。ちょっと見た限りでは無さそうだった。 Robolectricのドキュメントは薄すぎる・・・わからないことがあったらRobolectricのテストコードを読むのが多分一番いい。

参考:

http://robolectric.blogspot.jp/2013/04/the-test-lifecycle-in-20.html http://www.ne.jp/asahi/hishidama/home/tech/java/reflection.html