TL;DR
Android Studioでテストをエラーなく、かつ高速に実行できるようになるまでの手順があまりに多いので、最新の手順をまとめてみた。
テストコードの準備、またはRobolectricの導入
app/bulid.gradleに依存関係を追加
dependencies {
...
testCompile 'org.robolectric:robolectric:2.4'
}
最新版を公式で確認して下さい。
CustomRobolectricTestRunnerを設置
public class CustomRobolectricTestRunner extends RobolectricTestRunner {
public CustomRobolectricTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
String buildVariant = (BuildConfig.FLAVOR.isEmpty() ? "" : BuildConfig.FLAVOR + "/") + BuildConfig.BUILD_TYPE;
System.setProperty("android.package", BuildConfig.APPLICATION_ID);
System.setProperty("android.manifest", "build/intermediates/manifests/full/" + buildVariant + "/AndroidManifest.xml");
System.setProperty("android.resources", "build/intermediates/res/" + buildVariant);
System.setProperty("android.assets", "build/intermediates/assets/" + buildVariant);
}
}
(※Resource not foundなどというエラー出たら補足を参照のこと)
Robolectricを参照するテストコードにannotationを追加
@Config(emulateSdk = 18)
@RunWith(CustomRobolectricTestRunner.class)
public class FoobarTest {
@Test
public testHoge() {
Context context = Robolectric.applciation.getApplicationContext();
Foobar foobar = new Foobar(context);
...
}
}
Android Studioの設定
Run ConfigurationsでJUnit用のWorking Directoryを $MODULE_DIR$
に変更
追記:1.2.2のデフォルト設定では$MODULE_DIR$
になっています。
defaultを変更しておくと便利です。既存のConfigurationがある場合は書き換えるか消しておくとよいと思います。
Build VariantsのタブでTest ArtifactをUnit Testsに変更
デフォはAndroid Instrumentation Testsになってるはずです。
実行
全部実行はtest/javaディレクトリを右クリックすれば簡単にできます。1回実行すればRun Configurationsに追加されます。
テストの開始までが遅い場合
Run/Debug ConfigurationsのBefore launchで"Gradle-aware Make"のほかに"Make"とかの余計なものがないか確認します。
追記:1.2.2のデフォルト設定では、Makeだけが入ってました。下記の設定をしなければ、Makeにしておくほうがデフォルトに準拠していて良いかもです。
また、Android Studio 1.4未満はテスト実行に不要なapk作成までやってしまい遅いので、Gradle-aware Makeにtaskの設定をするともう少し早くなります。
FooBarの部分は"Debug"など、 現在の Build Variantに該当する名前を書きます。
補足
Robolectric
Androidの機能を使うテストは本来は実機やエミュレータで実行しなくてはなりませんが、このライブラリを使うとPC上で高速に実行できるようになります。
CustomRobolectricTestRunner
元ネタ:https://github.com/robolectric/robolectric-gradle-plugin/issues/142#issuecomment-103962546
なぜ必要か
RobolectricのJavaライブラリに、buildされたresource群やAndroidManifestファイルの位置を知らせるために必要です。
これがないとgetResources()やgetString()を叩くなどするとresourceが見つからない旨のエラーが出ます。
別の対応としてrobolectric-gradle-pluginもありますが、Android StudioでJUnit実行するとgradleを介さず起動するので、効果がありません。なので、pluginでやってることをCustomRobolectricTestRunnerにやらせます。
(余談ですが最近のrobolectric-gradle-pluginはRobolectricGradleTestRunnerが不要になったようです。)
Resource not foundのようなエラーが出る場合
build.gradleでapplicationIdを使い分けている等の場合は、android.packageのBuildConfig.APPLICATION_IDをデフォルトのapplicationId(恐らくAndroidManifest.xmlのandroid:package)に書き換えないとエラーが出ます。
直接パッケージ名を記載したくない場合はbuild.gradleにbuildConfigFieldを書くと便利です。
https://github.com/robolectric/robolectric-gradle-plugin/issues/142#issuecomment-112386932
@Config
robolectric 3.0ならemulateSdkは21までいけるらしいです。書き方が@Config(sdk = 21)
に変わっています。
robolectric 3.0ならapp/src/test/resources/robolectric.properties
にsdk=21
と記載すれば@Config
書かなくてすみます。( @kyanro@github さんありがとうございます!)
$MODULE_DIR$
gradleは最初からmoduleの中(/path/to/project/app)で実行してくれるんですが、Android StudioのJUnit実行のデフォルトはprojectディレクトリ(/path/to/project)になってます。
Before launchのGradle-aware MakeとMake
手元の環境だとなぜだか実行時に2回ビルドが走るのでおかしいなと思ったら、MakeとGradle-aware Makeの両方が入っていました。 もしかしたら自分でやったのかもしれない・・・。 @ainame も同じ設定になっていたらしいので、前のバージョンからのアップデートとかでなるのかもしれないです。