MultiDexが必要な状態でもRobospockでどうにかテストする


つい先日MultiDexが必要になってしまうことがありまして、その際にrobospockでテストが動かなくなりました
とりあえず強引に対応してみた備忘録です

結論だけ書くと、「それ用にbuild typeを追加した」になります

## robospockに関して

spockっていうテストフレームワーク+ Robolectric ですね

* [robospock](http://robospock.org/)

そんな本家サイト見ると…

* [robospock plugin](https://github.com/pjakubczyk/robospock-plugin/tree/f8d3f97add0fa2cb5d7957049dcab2b99f05c368) 使うんやで
  * 2015/01/07現在での最新コミットへのリンクにしています
* versionは0.4.4やで！

とかになっていますが、現状robospockは結構前から0.5.0になっていますし、0.5.0使おうとするとそのpluginじゃ駄目だし…

余談ですが前に[AndroidAnnotations + lombok と spock + Robolectric みたいな環境作ってみた](http://qiita.com/daneko0123/items/ead4617173cc8519d28e)なの書いています

がよく考えたら、今AndroidAnnotationもGuavaも使ってない~~し使いたくない~~

### robospock 0.5.0 でも gradle plugin使いたい

[現状有志で対応しているらしいです](http://sys1yagi.hatenablog.com/entry/2014/12/16/090000)

[Android StudioでRoboSpockを使えるようにする の記事でもその有志のplugin使っていますね](http://qiita.com/uunkotsu/items/e6fb5a9d19ca3be3e3a4)

### robospock本家sampleを参考にして、そもそもplugin使わない

[本家のsampleアプリを見ると、何気にplugin使ってません](https://github.com/Polidea/RoboSpock/blob/695ebd20e8d3739a5847611b980b6e9557731baf/sampleTest/build.gradle)

コンパイル結果のclassを集めてjarにして、それに対してテストするという手法を取っています

自分はその方法を真似てrobospockを使っています

## 本題

### とりあえずrobospockを使ってテストを書く

[とりあえずContextを利用した適当なテストを追加したProjectがこちらです](https://github.com/daneko/robospock_with_multidex_sample/tree/7efc6e12d2514275aa6b29a86258c2c981868eca)

Activityに対してテスト書きたいところですけど、[AcitionBarActivityにはまだ対応していない](https://github.com/robolectric/robolectric/issues/1332)ので上記のような適当な奴になっています

そんなこともあるんで、個人的にはrobospockは「Contextに依存するコードもUnitTestできる！」ぐらいの位置づけで使っています

### multidexを有効化する

[こんな感じでいっぱいlibraryを詰め込むとあっという間に65535を超えますね](https://github.com/daneko/robospock_with_multidex_sample/blob/0c64b71f52bdbf3747fa5696d62ded59bd7bc50d/app/build.gradle)

* support系やgmsは必須だし〜
* ViewInject系のライブラリは欲しいし〜
* ネットワークに繋げるのに楽なライブラリは欲しいし〜
* そうするとJsonのパースとか楽したいし〜

みたいな感じでガンガン入れてみたんですけどなかなか超えなかった…

multidexを有効化しないとこんなエラーが出ます

```
com.android.ide.common.internal.LoggedErrorException: Failed to run command:
        /usr/local/opt/android-sdk/build-tools/21.1.2/dx -JXmx4g --dex --no-optimize --output /private/tmp/android/MyApplication/app/build/intermediates/dex/debug --input-list=/private/tmp/android/MyApplication/app/build/intermediates/tmp/dex/debug/inputList.txt
  Error Code:
        2
  Output:

        UNEXPECTED TOP-LEVEL EXCEPTION:
        com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
                at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:502)
                at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:277)
                at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:491)
                at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:168)
                at com.android.dx.merge.DexMerger.merge(DexMerger.java:189)
                at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:454)
                at com.android.dx.command.dexer.Main.runMonoDex(Main.java:303)
                at com.android.dx.command.dexer.Main.run(Main.java:246)
                at com.android.dx.command.dexer.Main.main(Main.java:215)
                at com.android.dx.command.Main.main(Main.java:106)
```

ちなみにこの状態でメソッド数は

* 65344

でした

この段階で `./gradlew clean test:test` とかやっても動きます

### 4系でも動くApkを作るように…

[ここにあるようにやれば良いだけです](https://developer.android.com/tools/building/multidex.html#mdex-gradle)

[さっきとの差分](https://github.com/daneko/robospock_with_multidex_sample/commit/a9dc5ac4ac430229226e3fce6dd85ac36f7fb088)

この段階で `./gradlew clean test:test` とかやると…

```
com.example.myapplication.SampleSpec > classMethod FAILED
    java.lang.RuntimeException: java.lang.RuntimeException: Multi dex installation failed. SDK 1 is unsupported. Min SDK version is 4.

        Caused by:
        java.lang.RuntimeException: Multi dex installation failed. SDK 1 is unsupported. Min SDK version is 4.
```

とか出てきて大変残念な感じになります

他にも

```
error: package android.support.multidex does not exist
import android.support.multidex.MultiDexApplication;
```

とか

[本家のIssue](https://github.com/robolectric/robolectric/issues/1328)にも上がっているパターンとかも遭遇できて色々と辛いです

### とりあえずテストが動くようにする

前段の差分から、Manifestというか単にApplicationがMultiDexApplication使わなければ良いだけです

[なのでこうしました](https://github.com/daneko/robospock_with_multidex_sample/commit/389d6ad52c81e7b802904f678c8236bc3dcf4e16)

冒頭で書いた通り、build type を追加しただけです


## MultiDex避ければ基本問題ない

* [65K避けよう… とDocumentにはあります](https://developer.android.com/tools/building/multidex.html#avoid)
  * その為？なのかplay-servicesが細分化されていました(6.5.87から)
    * play-servicesが必要なものだけ入れられれば確かに助かる
    * extras/google/m2repository/com/google/android/gms/ 以下をみると次のような感じに

```
play-services
play-services-ads
play-services-all-wear
play-services-appindexing
play-services-appstate
play-services-base
play-services-cast
play-services-drive
play-services-fitness
play-services-games
play-services-identity
play-services-location
play-services-maps
play-services-panorama
play-services-plus
play-services-wallet
play-services-wearable
```

他にも上記Documentでも「Proguard」に関して触れていますが、
個人的にDebug/UnitTest如きで使いたくないってのがあります

最大の理由は **Buildに時間がかかってイライラするから**

ということで、もしMultiDex使わなければならない状況になって、且つrobospock使ってて動かなくなった！！
みたいなニッチな場合にご参考までにどうぞ

and もっと良い解決方法ください

and robolectric & robospock のversion up待ってる