Android Studio＆Robolectricでテストを正しく＆高速に動かす

# TL;DR

Android Studioでテストをエラーなく、かつ高速に実行できるようになるまでの手順があまりに多いので、最新の手順をまとめてみた。

## テストコードの準備、またはRobolectricの導入

### app/bulid.gradleに依存関係を追加

```groovy
dependencies {
    ...
    testCompile 'org.robolectric:robolectric:2.4'
}
```

最新版を[公式](https://github.com/robolectric/robolectric#install)で確認して下さい。

### [CustomRobolectricTestRunner](https://github.com/robolectric/robolectric-gradle-plugin/issues/142#issuecomment-103962546)を設置

```java
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を追加

```java
@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$`になっています。

![image](https://qiita-image-store.s3.amazonaws.com/0/4153/6ecc0ade-08d3-c297-ac37-276598f8b8ef.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/4153/99e45ac4-143d-9857-efe9-1b8563b3f652.png)

defaultを変更しておくと便利です。既存のConfigurationがある場合は書き換えるか消しておくとよいと思います。

### Build VariantsのタブでTest ArtifactをUnit Testsに変更

![image](https://qiita-image-store.s3.amazonaws.com/0/4153/c8e6ab83-ab0f-0a2c-7643-e765b6e327ab.png)

デフォはAndroid Instrumentation Testsになってるはずです。

### 実行

![image](https://qiita-image-store.s3.amazonaws.com/0/4153/45890cb6-f2cf-6d0c-b1a4-1d66336325e8.png)

全部実行はtest/javaディレクトリを右クリックすれば簡単にできます。1回実行すればRun Configurationsに追加されます。

### テストの開始までが遅い場合

Run/Debug ConfigurationsのBefore launchで"Gradle-aware Make"のほかに"Make"とかの余計なものがないか確認します。

![image](https://qiita-image-store.s3.amazonaws.com/0/4153/30554cd6-2c62-b7ce-7abb-0c07d8047fd6.png)

追記：1.2.2のデフォルト設定では、Makeだけが入ってました。下記の設定をしなければ、Makeにしておくほうがデフォルトに準拠していて良いかもです。

また、[Android Studio 1.4未満はテスト実行に不要なapk作成までやってしまい遅い](https://code.google.com/p/android/issues/detail?id=156256#c10)ので、Gradle-aware Makeにtaskの設定をするともう少し早くなります。

![gradle-aware-make.png](https://qiita-image-store.s3.amazonaws.com/0/4153/37ddf544-6135-5b87-f41a-c8ee01f55a15.png)

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](https://github.com/robolectric/robolectric-gradle-plugin)もありますが、Android StudioでJUnit実行するとgradleを介さず起動するので、効果がありません。なので、pluginでやってることをCustomRobolectricTestRunnerにやらせます。
（余談ですが最近の[robolectric-gradle-plugin](https://github.com/robolectric/robolectric-gradle-plugin)は[RobolectricGradleTestRunner](https://github.com/JakeWharton/gradle-android-test-plugin/blob/master/example/src/test/java/com/example/RobolectricGradleTestRunner.java)が不要になったようです。）

### 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 も同じ設定になっていたらしいので、前のバージョンからのアップデートとかでなるのかもしれないです。