表題の環境にてテストを実行した時にテストが全コケなんて事になってしまったので、その解決の過程なんかをまとめてみます。
Androidでテストするとき、Roboletlicを使うとエミュレーターへの接続が無かったりして高速にできるし便利です。
ということで導入してちょこちょこテスト書きつつ品質上げていこうな!と思っていました。
さらにアプリの品質を向上させるため、メモリリーク発生時に検出してくれるクールなLeakCanaryを導入してみました。
Robolectricはこの辺りや
http://qiita.com/yuya_presto/items/d5cc27225a19e1971096
LeakCanaryはこの辺を
http://qiita.com/rejasupotaro/items/4a8cfe0abda2d83145dd
参考にさせていただきました。ありがとうございます。
さて本題ですが、前述のとおり上記環境においてテスト全コケしてしまいました。
何が起こったのか
テスト全コケのそれ以上でもそれ以下でもないですが、それだけだと雑なので…
特定のBuildVariantsにおいて、Roboletlicでテストを走らせる際にLeakCanaryのインストールに失敗していたというのが原因になります。
どういうことですか
LeakCanaryを使用する際はApplicationClassに一行
LeakCanary.install(this);
としてあげれば済むのですが、これは端末にLeakというアプリを同時にインストールすることになります。
なので、リリースバージョンやテスターさんに配布するバージョンにおいては、このLeakアプリは見せたくないですよね。
ですので、gradleに以下の様な感じでdependenciesを書いてあげることになります。
betaCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
この状態でテストを回すと、betaCompileでのテストだけこけてしまいます。
とりあえずサンプルプロジェクトを作ってみました。
LeakCanaryやRoboletlicの導入なんかに関しては省略させていただきます。
プロジェクトはこちら。
https://github.com/wakwak3125/LeakCanaryTest
まずはApplicationクラスを継承した、MyApplicationです。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
次に、テストです。テストケースはそのままにしてあります。
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, packageName = "com.wakwak.leakcanarytest")
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
build.gradleはこんな感じ。
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.wakwak.leakcanarytest"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
beta {
minifyEnabled false
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
compile 'com.android.support:appcompat-v7:23.1.1'
betaCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
}
でUnitTestを実行するコマンドが
リリースバージョンが./gradlew testReleaseUnitTest
ベータバージョンが./gradlew testBetaUnitTest
となります。では実行してみましょうまずは、Releaseから。
./gradlew testReleaseUnitTest
:app:preBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:checkReleaseManifest
:app:preBetaBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72311Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42311Library UP-TO-DATE
:app:prepareComSquareupLeakcanaryLeakcanaryAndroidNoOp14Beta1Library UP-TO-DATE
:app:prepareReleaseDependencies
:app:compileReleaseAidl UP-TO-DATE
:app:compileReleaseRenderscript UP-TO-DATE
:app:generateReleaseBuildConfig UP-TO-DATE
:app:generateReleaseAssets UP-TO-DATE
:app:mergeReleaseAssets UP-TO-DATE
:app:generateReleaseResValues UP-TO-DATE
:app:generateReleaseResources UP-TO-DATE
:app:mergeReleaseResources UP-TO-DATE
:app:processReleaseManifest
:app:processReleaseResources
:app:generateReleaseSources
:app:processReleaseJavaRes UP-TO-DATE
:app:compileReleaseJavaWithJavac
:app:preReleaseUnitTestBuild UP-TO-DATE
:app:prepareReleaseUnitTestDependencies
:app:processReleaseUnitTestJavaRes UP-TO-DATE
:app:compileReleaseUnitTestJavaWithJavac
:app:compileReleaseUnitTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:assembleReleaseUnitTest
:app:testReleaseUnitTest
BUILD SUCCESSFUL
Total time: 13.652 secs
成功ですね。
次に、Betaのテストを走らせます。
./gradlew testBetaUnitTest
:app:preBuild UP-TO-DATE
:app:preBetaBuild UP-TO-DATE
:app:checkBetaManifest
:app:preDebugBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72311Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42311Library UP-TO-DATE
:app:prepareComSquareupLeakcanaryLeakcanaryAndroid14Beta1Library UP-TO-DATE
:app:prepareBetaDependencies
:app:compileBetaAidl UP-TO-DATE
:app:compileBetaRenderscript UP-TO-DATE
:app:generateBetaBuildConfig UP-TO-DATE
:app:generateBetaAssets UP-TO-DATE
:app:mergeBetaAssets UP-TO-DATE
:app:generateBetaResValues UP-TO-DATE
:app:generateBetaResources UP-TO-DATE
:app:mergeBetaResources UP-TO-DATE
:app:processBetaManifest UP-TO-DATE
:app:processBetaResources UP-TO-DATE
:app:generateBetaSources UP-TO-DATE
:app:processBetaJavaRes UP-TO-DATE
:app:compileBetaJavaWithJavac UP-TO-DATE
:app:preBetaUnitTestBuild UP-TO-DATE
:app:prepareBetaUnitTestDependencies
:app:processBetaUnitTestJavaRes UP-TO-DATE
:app:compileBetaUnitTestJavaWithJavac UP-TO-DATE
:app:compileBetaUnitTestSources UP-TO-DATE
:app:mockableAndroidJar UP-TO-DATE
:app:assembleBetaUnitTest UP-TO-DATE
:app:testBetaUnitTest
com.wakwak.leakcanarytest.ExampleUnitTest > addition_isCorrect FAILED
java.lang.RuntimeException
Caused by: java.lang.NullPointerException
1 test completed, 1 failed
:app:testBetaUnitTest FAILED
FAILURE: Build failed with an exception.
というわけで解決策
ということで解決方法なんですが、これが正解かどうかはわかりませんが、Multidex
を有効にした際にテストを走らすときのエラーと似ているような感じがしたので、MyApplicationクラスを以下のように変更しました。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
LeakCanary.install(this);
} catch (Exception ignore) {
}
}
}
LeakCanary.install(this);
をtry~catchで囲んであげるだけです。
こうすることによって上記のエラーを回避することができます。
releaseCompileではなぜ上記のようなエラーが起きないかといいますと、LeakCanaryはno-opの際はLeakアプリをインストールしないからだと思われます。(この辺ちゃんとソース読むと解決すると思いますが、さっと見た感じ何もしていないようでした。)
というわけで、LeakCanaryを有効にし、Roboletlicでテストを走らせる際は上記のような対応をしてあげると良いと思われます。
もし私の勘違いや間違いなどアレば指摘していただけますと幸いです。
今回の件はアタリマエのことかもしれませんが、最初は面食らってしまったのでまとめてみました。
それでは…