Androidテスト導入入門 - Why don't you write a test ?

# Why don't you write a test ?
Androidでユニットテストを書くまでの流れを雑にまとめた（2015/8/12時点）．

## runner
Androidでいい感じにunit testingするためのライブラリには[**Robolectric**][robolectric]や[**Testing Support Library**][testing-support-library]が有名．[Testing Support Library][testing-support-library]は実機やEmulator上でテストを走らせるのに対し，[Robolectric][robolectric]はDalvik/ARTじゃなく普通のJVMで走らせるので早い代わりに挙動が異なる可能性がある
．
今回は公式に提供されている[Testing Support Library][testing-support-library]を利用する．
しかし，[Robolectric][robolectric]の方がShadow Objectいっぱいあったりと高性能ではあるので状況次第．

```groovy
android {
    // 省略

    defaultConfig {
        // 省略
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    packagingOptions {
        exclude 'LICENSE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE'
    }
    // 省略
}
```

```groovy
dependencies {
    // 省略

    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile 'com.android.support.test:rules:0.3'
}
```

これで以下のコマンドでテストが走るようになる（Android StudioからRunさせることも可能）．
要エミュレータ or 実機．

```shell-session
$ ./gradlew connectedAndroidTest
```

## assertion
JUnit4におけるassertionでは[hamcrest][hamcrest]がメジャーである（？）が，ここではよりクールにテストが書ける[**AssertJ**][assertj]を利用する．
[AssertJ][assertj]はRubyにおけるRSpecやJSにおけるJasmine，Mochaのようなインタフェースで利用でき，Spec形式のテストに慣れている人間には取っ付き易い．

しかし，[AssertJ][assertj]の2系はJava 7，3系はJava 8が必須となりややこしい．
square社がAndroid用便利Matcher等を追加した[AssertJ Android][assertj-android]を提供しており，Androidでも動作するよAssertJのバージョンも調整してくれているので，それを利用する．

```groovy
dependencies {
    // 省略

    androidTestCompile 'com.squareup.assertj:assertj-android:1.0.1'
}
```

## mock/stub/spy
mock/stub/spyには[**Mockito**][mockito]および[Dexmaker][dexmaker]を利用する．
`final`なクラスのmock化をしたい場合などは[PowerMock][powermock]があるが，どうも[Dexmaker][dexmaker]と相性が悪いらしい（参考: [java - How to get Powermock to work with Dexmaker - Stack Overflow][powermock-dexmaker]）．

さらに，[Dexmaker][dexmaker]は最新版（1.4.0）だと正常に動作しないっぽいのでちょっと古いやつを利用する必要がある（参考: [Unable to run tests with Android and 1.3 · Issue #18 · crittercism/dexmaker][dexmaker-issue]）．

```groovy
dependencies {
    // 省略

    androidTestCompile 'org.mockito:mockito-core:1.9.5'
    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
}
```

AndroidのAPIにあるfinalクラスをMockにしたい場合とかはおとなしくRobolectric使ったほうがいいかもしれない．

## CI
Circle CIやTravis CIなど種類は色々あるけど，ここではWerckerを利用する．
ここでは割愛するが，例えばmasterへのマージ後にCIパスしたらbintrayにdeployする みたいな処理を扱いやすいのがポイント．

```yaml
box: wercker/android
build:
  steps:
    - script:
        name: show base information
        code: |
          gradle -v
          echo $ANDROID_HOME
          echo $ANDROID_BUILD_TOOLS
          echo $ANDROID_UPDATE_FILTER
    - android-sdk-update:
        filter: platform-tools,extra-android-m2repository,extra-android-support
    - setup-android-emulator:
        target: android-22
    - script:
        name: run gradle connectedAndroidTest
        code: |
          gradle --full-stacktrace -q --project-cache-dir=$WERCKER_CACHE_DIR connectedAndroidTest
  after-steps:
    - script:
        name: inspect build result
        code: |
          pwd
          ls -la ./app/build/outputs/
          cp -r ./app/build/outputs/* ${WERCKER_REPORT_ARTIFACTS_DIR}
```


# References

* [Testing Support Library | Android Developers][testing-support-library]
* [2015年7月時点でのJUnit4やEspressoを使ったAndroidアプリのテストについて - Qiita][qiita-shikato-junit4]
* [Androidのビルドとテストをwerckerで自動化する - Qiita][qiita-cattaka-wercker]
* [Unable to run tests with Android and 1.3 · Issue #18 · crittercism/dexmaker][dexmaker-issue]

## Libraries

* [Robolectric][robolectric]
* [hamcrest][hamcrest]
* [AssertJ][assertj]
* [AssertJ Android][assertj-android]
* [Mockito][mockito]
* [PowerMock][powermock]


[testing-support-library]: https://developer.android.com/tools/testing-support-library/index.html
[qiita-shikato-junit4]: http://qiita.com/shikato/items/e4fa620f0f616d6b790d
[qiita-cattaka-wercker]: http://qiita.com/cattaka/items/40ac055bf5a67cb57d9d
[powermock-dexmaker]: http://stackoverflow.com/questions/27953270/how-to-get-powermock-to-work-with-dexmaker
[dexmaker-issue]: https://github.com/crittercism/dexmaker/issues/18

[robolectric]: http://robolectric.org/
[hamcrest]: https://github.com/hamcrest/JavaHamcrest
[assertj]: http://joel-costigliola.github.io/assertj/
[assertj-android]: http://square.github.io/assertj-android/
[mockito]: http://mockito.org/
[dexmaker]: https://github.com/crittercism/dexmaker
[powermock]: https://github.com/jayway/powermockv