(追記: このハックはライブラリとして独立させました gfx/RobolectricInstrumentation · GitHub)
Robolectricは便利ですが、Oracle JREとAndroid Runtimeの微妙な挙動の違い、特にAndroid Runtimeにバグの回避するようなコードのテストができないという問題があります。
ところでRobolectricを純粋にJVM用のAndroid Frameworkランタイムとみなすと、テストクラスをほとんどAndroid Instrumentation Testsと同じように書くことができます。
Robolectricのほうがテストの実行が速いので、開発中はRobolectricを使うほうが効率はいいのですが、微妙に挙動に違いがあるので実機でもテストは走らせたいところです。そこで同じテストクラスをAndroid Instrumentation TestsとRobolectric Tests両方で走らせられると、RobolectricとInstrumentation Testsの双方のメリットを享受できます。そう考えて工夫した結果、Robolectric用にダミーのAndroid Testing Frameworkを実装することでうまくいきました。
ダミーのAndroid Testing Frameworkといっても、追加したのは AndroidJUnit4
と InstrumentationRegistry
だけです。同時に、もともとあったテストクラスからrobolectric依存をなくし、Android Testing Frameworkに移植しました。つまり全体としてはRobolectric APIで実装したAndroid Test Frameworkのラッパーを作った形です。
なお、逆のパターン、つまりAndroid Testing Framework APIで実装したRobolectricのラッパーも試してみたのですが、Android Testing Frameworkの一部が android.support.test.runner.AndroidJUnit4
のクラスインスタンスそのものに依存していてラッパーを受け付けなかったので断念しました。
結果、コードはこのような形になりました。
今回のケースではAndroid Testing FrameworkやRobolectricの機能をほとんど使っていなかったので、テストコード自体の書き換えはほとんど不要でした。テストの実行は ./gradlew test
が40秒、 ./gradlew connectedAndroidTest
が1分30秒なので、開発中はRobolectricでテストをし、ときどき(あるいはCIで) ./gradlew connectedAndroidTest
で確認するというのがよさそうです。