現象
Instrumentation TestでMockitoをKotlinで使うため、以下のようにライブラリを設定して使っていました。
androidTestImplementation 'org.mockito:mockito-core:3.9.0'
androidTestImplementation ('org.mockito.kotlin:mockito-kotlin:3.1.0'){
exclude group: 'org.mockito', module: 'mockito-core'
}
androidTestImplementation ('com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1'){
exclude group: 'org.mockito', module: 'mockito-core'
}
ところが、P(Android9)の端末(エミュレーター)では問題なく動作するのに、Q以上(Android10)以上の端末orエミュレーターで動かそうとするとモックに失敗してしまいました。
エラーメッセージ
java.lang.NullPointerException: Attempt to invoke interface method 'boolean org.mockito.plugins.MockMaker$TypeMockability.mockable()' on a null object reference
at org.mockito.internal.util.MockCreationValidator.validateType(MockCreationValidator.java:23)
at org.mockito.internal.creation.MockSettingsImpl.validatedSettings(MockSettingsImpl.java:250)
at org.mockito.internal.creation.MockSettingsImpl.build(MockSettingsImpl.java:232)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:61)
at org.mockito.Mockito.mock(Mockito.java:1951)
at org.mockito.Mockito.mock(Mockito.java:1862)
解決方法
どうやら64bitライブラリが問題?なようで、以下の設定を行うと解消しました。
androidTest用のマニフェストファイルを作成する
androidTest
下に、AndroidManifest.xmlを作成し、以下のように記述します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.package">
<application android:extractNativeLibs="true" />
</manifest>
これだけで、テストが通るようになりました。
解決方法に辿り着いた経緯
mockito-kotlinが使えないなら、MockKを使ってみようと思い変更したのですが、やはり同じで、Android Pでは動いて、Q以上では動かない。
ただしエラーメッセージは異なっていました。
Caused by: io.mockk.proxy.MockKAgentException: MockK could not self-attach a jvmti agent to the current VM. This feature is required for inline mocking.
This error occured due to an I/O error during the creation of this agent: java.io.IOException: No such file or directory
Potentially, the current VM does not support the jvmti API correctly
at io.mockk.proxy.android.AndroidMockKAgentFactory.init(AndroidMockKAgentFactory.kt:63)
at io.mockk.impl.JvmMockKGateway.<init>(JvmMockKGateway.kt:46)
at io.mockk.impl.JvmMockKGateway.<clinit>(JvmMockKGateway.kt:172)
このメッセージでググって、辿り着いたのが以下のissue.
ここで64bit向けのライブラリがapkにないせいではないかと指摘されており、コメントで提案されていた案の1つを試してみたところ上手くいきました。
そこで、mockito-kotlinに戻してみて同じように設定し、テストを動かしてみたら無事に動いた、というわけです。
android:extractNativeLibsについて
こちらのページによれば、android:extractNativeLibs
はデフォルトでtrue
らしいのですが、Instrumentationテスト実施時には違う、ということでしょうか。。。
(でも、実機は説明付くんだけど、エミュレーターのimageはx86
で、x86_64
じゃないんだけどな・・・・動かしているマシンが64bitだからそちらに引っ張られるんだろうか?)
追記
AGP(Android Gradle Plguin)3.6.0から、デフォルトはfalse
に変わったようです。
mockito-kotlinとMockKを同時に使う方法
MockKに置き換える際、いっぺんに変えるのは無理だったので単純なテストだけ置き換えたのですが、その際、mockito-kotlinとMockKに単純に同時に依存するとテストが実行出来ませんでした。
(エラーメッセージは忘れてしまいましたが、ビルドの時点で失敗したと思います)
以下のサイトが参考になりました。
https://medium.com/monsterculture/how-to-use-mockito-together-with-mockk-in-android-instrumentation-tests-c8d022fac04e