heihei blog

書けるときに書く。📝

Robolectric 4.2の変更点とアップデートできずに詰まっている点について

f:id:shaunkawano:20190312231526p:plain

Robolectricとは

RobolectricとはAndroidのためのオープンソースのユニットテストフレームワークです。レミュレータや実機を起動してテストを実行せずとも、JVM内の擬似的Android環境上でテストを実行することで、テスト実行時にActivityなどのAndroidプラットフォームのクラスを利用・テストできます。

github.com

Robolectric 4.2

一ヶ月弱前に、最新バージョンとして4.2がリリースされました。

※詳しくはrobolectricのreleaseページを御覧ください。

今回のリリース含め、DeprecatedになったAPI一覧はこちらです:

robolectric.org

デバイス上での実行時と挙動を同じにする

Robolectric 4.2からは、Robolectricテスト実行時の挙動とデバイス上でテストを実行した時の挙動を統一するような変更が行われています。

具体的には、今までRobolectricを使ってActivityを起動するようなテストやContextを用いたテストを実行するためにActivityを起動する際のテストを記述する際には、下記のようにしていました。

val scenario = ActivityScenario.launch(FragmentActivity::class.java)
...

scenario.onActivity {
  ... // assert some text with activity as `it`
}

今回の変更から、Robolectricを用いたテストではこのようなActivit起動の指定の仕方はNPEで落ちるというような挙動となっています。そしてこれは、Robolectric側の意図した挙動となっています。

どういうことかというと、今まで上記のような指定でActivity起動をしていた際には、Robolectricでは暗黙的かつ自動的にAndroidManifestのエントリーを作成しテストが実行できるように制御してくれていたのですが、それはRobolectric独自の挙動でありデバイス上での実行時と挙動が異なるものであったため、バージョン4.2からは自動でそのような自動生成だったり独自制御をせず、基本的にはAndroidFrameworkの挙動に準拠するようになった、ということになります。

デバイス上での実行と仮想環境での実行を統一するという流れは理にかなっているかと思います。

なので今後RobolectricでActivitを用いたテストを実行する際には、実際のAndroidManifest.xmlにテストで利用するActivityを定義しておいて、それをテスト時に参照する、ということが必要となります。

未解決の課題

ただ、執筆時点では、最新バージョンに上げるためには、まだ課題が残っています。どういう課題かというと、現状のAndroid Gradle Pluginの課題(もしくはRobolectric側で解決できる課題?)として、testImplementationで指定したモジュール内のAndroidManifest.xmlをマージしてくれないというものです。

https://issuetracker.google.com/issues/127986458

この解決策として、Robolectricのレポジトリのissueには、テスト専用のモジュール(たとえばtestsupportモジュール)をプロジェクト内で定義した場合には、そのモジュールをapp/build.gradle側でimplementationしつつ、testsupport/build.gradleではimplementation project(':app')することで暫定対応できるとの紹介がされています。

github.com

ただ、素直にこの解決策をサンプルレポジトリを作って試してみたのですが、自分ではうまく解決できなかったため、今のところアップデートできずに詰まっているという状態です。

具体的にどういう実装になっているかご覧になりたい方は下記をご覧ください。

github.com

自分の指定の方法が間違っている、勘違いしている箇所がある、ということはかなりありえるので、なにか気づいたことなどあればコメントなどでご教授いただけると幸いです🙏

アップデートに成功した際には、下に追記していく形でこの記事を更新していく所存です。

以上、詰まってアップデートできていない、という話でした。