はじめに
Androidでユニットをテストを記述し、自動で実行する場合にはエミュレータや実機の接続が必要です。ところが、エミュレータの場合は起動時間や動作の速度が気になりましたし、実機の場合はCIサーバーの利用が難しい問題がありました。しかし、Version 1.1以降のAndroid Gradle PluginそしてAndroid Studioを利用することで一部のテストをJVM上で実行することができます。
Androidのコンポーネントをそのままでは利用できないですが、エミュレータを起動したり実機と接続をする必要も無いので、うまく利用すればテストにかかるコストを抑えることができるでしょう。
やりかた
何はなくとも、Android gradle pluginのバージョンが1.1以上になっていることを確認しましょう。
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
次に依存関係を解決します。
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
}
最後に、android.jar
に含まれるメソッドをこのまま呼び出すと容赦なく例外を吐いて落ちていってしまうので、対応をします。
android {
testOptions {
unitTests.returnDefaultValues = true
}
}
とりあえずこれで準備ができました。
また、Android StudioのBuild Variants
のTest Artifact
をUnit Tests
に変更します。
テストを書く
あとはJUnit4の書式でテストを書いていきます。テストコードはsrc/test/java
以下へ格納します。context
などのAndroid用のAPIはMockitoとMockContextなどで代用をします。例えば、AssetManager
を返すcontextを用意する場合、
class MyContext extends MockContext {
@Override
public AssetManager getAssets() {
final AssetManager assetManager = mock(AssetManager.class);
final InputStream is = Hogehoge.class.getClassLoader().getResourceAsStream("myfile.json");
assertThat(is, is(notNullValue()));
try {
when(assetManager.open("myfile.json")).thenReturn(is);
} catch (IOException e) {
throw new RuntimeException(e);
}
return assetManager;
}
}
といった具合に、自分の好きな値を返すモックを用意できます。
テストの実行は./gradlew :app:testDebug
から。
まとめ
AndroidのユニットテストをJVM上で実行する方法を説明しました。実際に利用をした感じですが、モックの準備が手間であること、jni
のライブラリをロードすることができないこと、リソースへアクセスすることができない(?)ために、利用できるシーンに制限はあるなって感じです。robolectricの方が提供される機能としては豊富なのかな?とも思いました。
しかし、UIを利用しないAndroidのコンポーネント(Service, Broadcast Receiver, Content Provider)やその他ロジック部分のみについては十分に使えるとも思いました。利用シーンをよく見極めて、開発効率向上と品質の維持を行いたいですね。