AndroidのUnit Tests
AndroidでUnit Testsを書いていると、次のようなエラーが出ました。
java.lang.RuntimeException: Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
原因は、Unit TestsなのにAndroidのクラスであるLog.d()
を使っている場所があることです。
Androidに関係する部分と関係しない部分を明確に分けて書くことは、コードの見通しを良くしたり、Unit Testsをしやすくしたりする効果がありますが、Logなどはどうしてもいろいろなところに入ってきてしまうと思います。
そういう時に、テストをするための3つの方法を紹介します。
testOptionsを設定する
エラーログのリンクにある方法ですが、build.gradleに以下を追加します。
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
これを設定すると、Unit Testsで全てのAndroidクラスが何もしないようになります。
しかし、気付かぬうちにAndroidのクラスを使っていると、テストの振る舞いが想定しているものと違うことになってしまい、はまってしまうことがあると思います。
Robolectricを使う
RobolectricはAndroidのクラスをエミュレートすることで、エミュレータを起動せずにテストするものです。
build.gradleに以下を追加します。
dependencies {
// ...
testCompile 'org.robolectric:robolectric:3.0'
}
テストクラスでは、以下のように書きます。
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class HogeTest {
// ...
}
これで、エラーは出なくなりますが、どうしても微妙に速度が遅くなるという問題はあります。
PowerMockを使う
PowerMockは、static関数のMockを作ることができるライブラリです。
build.gradleに以下を追加します。
dependencies {
// ...
testCompile 'org.powermock:powermock-module-junit4:1.6.3'
testCompile 'org.powermock:powermock-api-mockito:1.6.3'
}
テストクラスでは、以下のように書きます。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)
public class HogeTest {
@Test
public void testHoge() {
PowerMockito.mockStatic(Log.class);
// ...
}
}
これならば、LogクラスだけをMockすることができます。
まとめ
いかがでしたでしょうか?
個人的にはPowerMockを使う方法が一番いいかなと思います。
ただ、公式で次のように言っているので、改善されることを気長に待つのがいいかもしれません。
We are aware that the default behavior is problematic when using classes like Log or TextUtils and will evaluate possible solutions in future releases.