第9回potatotipsでRobolectricでPowerMockを使う方法を発表しました #potatotips
2014/9/24(水)に開催された【第9回】potatotips(iOS/Android開発Tips共有会)で発表してきました。以下が発表資料です。
Androidの単体テストフレームワークRobolectricでPowerMockを使う方法(開発環境にAndroid Studioを使う場合)を紹介する内容です。
当日の発表は、持ち時間が5分ということもあり、ほとんど結論だけの内容にしたのですが、このエントリーでは、この結論に至った経緯について少し補足したいと思います。
JDKのバージョンについて
RobolectricとPowerMockを共存させるために利用しているPowerMockAgentの問題で、JDK1.7でテストを実行しようとすると、以下のような例外が発生し、実行に失敗してしまいます。
java.lang.IllegalStateException: Unable to load Java agent; please add lib/tools.jar from your JDK to the classpath
この問題は、PowerMockのissueに登録されていて、Mavenを使う場合の回避策は書かれているのですが、Gradle/Android Studioで解決する方法がわかりませんでした。
具体的には、テスト実行時に-javaagent
オプションに加えて-XX:-UseSplitVerifier
を指定すればうまくいきそうなのですが、自分の環境では解決しませんでした。
この点を解決する方法が見付かれば、JDK1.7以降でも動作させることができると思います。
robolectric-gradle-pluginのバージョンについて
発表時点におけるrobolectric-gradle-pluginのリリースバージョンは0.12.0だったのですが、0.12.0ではテスト実行時のオプション引数を指定するためのjvmArgs
機能が実装されていませんでした。
PowerMockAgentの方法を使ってテストを実行するときは、テスト実行時に-javaagent
オプションを使って、powermock-module-javaagent-1.5.5.jar
へのパスを指定する必要があります。
そのため、jvmArgs
機能が実装されているmasterブランチの先端(資料作成当時のリビジョンはこちら)を自分でビルドする方法を紹介したのですが、今確認したら、発表当日に0.13.0がリリースされていたようです。
0.13.0にはjvmArgs
を指定できる機能も含まれているようなので、こちらを利用すれば、わざわざ自分でビルドする必要はなさそうです。まだ0.13.0での動作確認はできていないので、近々確認してみようと思います。
RobolectricのConfigファイルの配置について
Robolectricでテストを実行するには、テスト対象アプリのAndroidManifest.xml
の場所をorg.robolectric.Config.properties
ファイルに指定する必要があります。
このファイルを置くディレクトリについて、発表ではsrc/test/res
と説明しましたが、少なくともrobolectric-gradle-pluginの0.12.0ではsrc/test/resources
が正しい置き場所でした。
その後のどこかでsrc/test/res
配下を見るように仕様変更したようなのですが、意図したものなのかバグなのか分かっていません。今後またsrc/test/res
から変更されるかも知れませんので、うまくテスト対象アプリが見付けられていないようなら、このファイルが正しく読み込まれているかどうか、以下の方法で確認してみると良いと思います。
gradle clean testDebugClasses
を実行する。build/test-classes
ディレクトリにorg.robolectric.Config.properties
ファイルが存在するかどうかを確認する。存在していれば問題なし。
Android Studioで実行できるようにするための設定について
Android StudioでRobolectricのテストを実行する方法については、id:STAR_ZERO さんによる以下の記事が非常に参考になりました。
この記事に書かれている内容をrobolectric-gradle-pluginの最新版に対応させ、PowerMock対応のための実行時オプションを追加したものが、今回の発表のベースになっています。
Javaエージェント方式 vs JUnit Rule方式
RobolectricとPowerMockの併存が難しい根本的な理由は、JUnit4の@RunWith
アノテーションで指定できるテストランナーが1クラスに限定されているからです(発表スライドp.8参照)。一方、PowerMockには@RunWith
を使わない方法として、以下の2通りが用意されています。
このどちらの方法を採用しても、@RunWith
の問題を解決できるはずですなのですが、自分の環境では、JUnit Rule方式ではXStream周りで例外が出て起動に失敗してしまい、うまく動作しませんでした。
そのような経緯で、Javaエージェント方式を採用したのですが、Javaエージェント方式は公式ドキュメントにexperimentalと書かれていることもあり、もし例外発生を回避できる方法が見付かるなら、JUnit Rule方式がより望ましいと思います。
JUnit Rule方式を使うことができるようになれば、JDK1.6縛りの問題も解決されますし、-javaagent
オプションをテスト実行時に指定する必要がなくなるため、build.gradle
もかなりシンプルになるはずです。
もし解決方法をご存知の方がいらっしゃいましたら、コメントいただけると有り難いです。
さいごに
potatotipsに参加するのは今回が2回目だったのですが、前回と同様、どの発表も自分にとっては知らないことばかりで、「今度機会があったら使ってみよう」と思えるTipsが揃っていました。自分の発表もそのように感じて下さった方がいらっしゃったとしたら大変嬉しいです。
発表後の懇親会では、Androidアプリ開発にまつわる色々な視点の話を伺うことができ、とても参考になると共に、楽しい時間を過ごすことができました。自分では思い至らないような視点を持っている方が多く、自分ももっと視野を広げねば、と思った1日でした。また何かネタを見つけて発表したいと思います!
主催してくださった @ninjinkun さんを始めとするFablic,inc.の皆さん、運営サイドの皆さん、どうもありがとうございました。