Mutlidexを使ってる時にAndroidTestが動かない問題とその対処方法

お久しぶりです。くぎみやです。

## 問題発覚

`AndroidKeyStore` を使っていて、 `encrypt` して `decrypt` できるかのテストを書こうと思いました。特にここら辺はHWも関わってくるところであるために、モックなど使わずにサボらずに実機 (or エミュレータ)でテストを書こうと思ったのが始まりでした。

`encrypt` したものを `decrypt` し、元のテキストになるかのテストを書き、 Android8.1のエミューレータで動かしたところ、テストはしっかり動きました。そして、いくつか修正して最終的に `SUCCESS`の文字がターミナルにでて来ました。

いつもであればこれで良しとするのですが、 `AndroidKeyStore`周りのAPIがAndroid6.0から結構変わっておりまして、そのためminSDKのバージョンに指定しているAndroid4.3でも試して見たところ問題が発生しました。

```
com.android.builder.testing.ConnectedDevice > No tests found.[Nexus_5X_API_18(AVD) - 4.3.1] FAILED 
No tests found. This usually means that your test classes are not in the form that your test runner expects (e.g. don't inherit from TestCase or lack @Test annotations).
```

ちなみに、AS上からテストファイルを開いて、テストクラスの左側に表示されてる単体実行のボタンを押すと、ちゃんと実行されて成功するんですよね...

## そのときの build.gradle

```groovy:build.gradle
android {

    defaultConfig {
        :
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    :
}
dependencies {
    :
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
```

これで、少なくともAndroid8.1のエミューレータではしっかり動くことを確認しています。

## 原因

https://issuetracker.google.com/u/1/issues/78108767

>The issue is that the main dex list for the test APK does not contain the test classes. AndroidJUnitRunner when looking for the test classes, does not uses the patched class loader that contains all dex files, but it only examines classes.dex. Therefore, it does not find any test classes to run.

ここに書いてあることが全てなのですが、補足しておくと `AndroidJUnitRunner` が `classes.dex` しか見てくれない、つまり `classesN.dex` などが無視されてしまうことが問題のようです。

mutlidexをtureにしているときは、こんな感じで複数のdexファイルができます。

<img width="764" alt="スクリーンショット 2018-04-27 12.33.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/47114/67d6966b-7b38-049f-6152-17f59b459752.png">

肝心のテストクラスを探してみると、 `classes2.dex` の中にあることがわかります。

<img width="660" alt="スクリーンショット 2018-04-27 12.39.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/47114/f0cce68c-6be1-c1f1-a03f-65ddb413c774.png">

`AndroidJUnitRunner` は `classes2.dex` は見ずに、 `classes.dex` しか見てくれない。
よって `No tests found.` ということらしいです。

## 解決策

https://issuetracker.google.com/u/1/issues/78108767

先ほどと同じリンクにworkaroundも書かれています。

> android.enableD8MainDexList=false
> 
> as this will make as keep all annotated classes in the main dex. Even though that is not the required for the legacy multidex to work, it will fix the issue for this particular case.

`gradle.properties` に `android.enableD8MainDexList=false` と記述することで解消するようです。

これを記述することで、アノテーション付きのクラスをmainのdexファイルに入れたままにできるそうです。

試して見たところ、 `build.gradle` に下記も必要でした。

```groovy:build.gradle
dependencies {
  : 
  androidTestImplementation 'com.android.support:multidex-instrumentation:1.0.3'
}
```

ここまでやって、ようやくAndroid4.3でもテストを通すことができました。

## 確認

念のため、 `keep all annotated classes in the main dex` これも確認しておきましょう。

<img width="666" alt="スクリーンショット 2018-04-27 12.49.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/47114/9727d995-09a9-bd38-ceea-61ec5114119c.png">

なるほど、たしかに `classes.dex` にてテストクラスを発見することができました。

## まとめ

multidex時にandroidTestを動かしたいなら、こんな感じ。

```groovy:build.gradle
android {

    defaultConfig {
        :
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    :
}
dependencies {
    :
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestImplementation 'com.android.support:multidex-instrumentation:1.0.3'
}
```

```gradle.properties
:
android.enableD8MainDexList=false
```