次のコードを実行すると:
public class ActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
....
public void testCanCreateMockito() {
List mockedList = Mockito.mock(List.class);
}
}
次の例外が発生します。
Java.lang.ExceptionInInitializerError
at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.Java:95)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.Java:57)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.Java:49)
at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.Java:24)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.Java:33)
at org.mockito.internal.MockitoCore.mock(MockitoCore.Java:59)
at org.mockito.Mockito.mock(Mockito.Java:1285)
at org.mockito.Mockito.mock(Mockito.Java:1163)
at com.acesounderglass.hungertracker.ActivityTest.testCanCreateMockito(ActivityTest.Java:60)
at Android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.Java:214)
at Android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.Java:199)
at Android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.Java:192)
at Android.test.AndroidTestRunner.runTest(AndroidTestRunner.Java:191)
at Android.test.AndroidTestRunner.runTest(AndroidTestRunner.Java:176)
at Android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.Java:555)
at Android.app.Instrumentation$InstrumentationThread.run(Instrumentation.Java:1837)
Caused by: org.mockito.cglib.core.CodeGenerationException: Java.lang.reflect.InvocationTargetException-->null
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.Java:238)
at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.Java:145)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.Java:117)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.Java:109)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.Java:105)
at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.Java:70)
... 23 more
Caused by: Java.lang.reflect.InvocationTargetException
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.Java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.Java:220)
... 28 more
Caused by: Java.lang.UnsupportedOperationException: can't load this type of class file
at Java.lang.ClassLoader.defineClass(ClassLoader.Java:300)
... 32 more
これはどのクラスでも発生します。リストは簡単な例です。私のgradleの依存関係は次のとおりです。
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.Android.support:appcompat-v7:21.0.0'
androidTestCompile "org.mockito:mockito-core:1.+"
androidTestCompile files('libs/dexmaker-mockito-1.0.jar')
androidTestCompile files('libs/dexmaker-1.0.jar')
}
私はgradleを1.1にアップグレードし、実験的な単体テスト機能を使用してみましたが、何も違いはありません。どうしたの?
2つのdexmaker依存関係が欠落しているときにこのエラーを受け取りました。
これらの行をapp/gradle.buildファイルに追加することは私にとってはうまくいきます。
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
また、Android Studioを使用していますが、依存関係を変更した後にASを再起動することをお勧めします。
私にとってこれは最終的に機能しました:
androidTestCompile "org.mockito:mockito-core:1.10.19"
androidTestCompile "com.crittercism.dexmaker:dexmaker:1.4"
androidTestCompile "com.crittercism.dexmaker:dexmaker-mockito:1.4"
androidTestCompile "com.crittercism.dexmaker:dexmaker-dx:1.4"
これは、65Kメソッドの制限のためにデバッグビルドにproguardを使用していたためです(はい、依存関係の数を減らす必要があります)。それがこのエラーの原因でした。
私はそれを解決するために私の(デバッグ)プロガード構成にこれを追加しました:
### Keep Mockito
-keep class org.mockito.** { *; }
-keep interface org.mockito.** { *; }
-keep class com.google.dexmaker.** { *; }
-keep interface com.google.dexmaker.** { *; }
これらの4行すべてが本当に必要かどうかはわかりませんが、これでうまくいきました。
GRADLEを使用してAPKを構築しない場合はこちらをご覧ください!!!!
Gradleを使用してアプリを構築しない場合(残念ながら、私のチームはそうしません)、上記のソリューションはうまくいかないかもしれません。この問題の解決策を示す前に、dexmaker-mockitoがどのように機能するかについてもう少し説明します。
動機
MockitoはJavaのモックフレームワークであり、バイトコードモックを作成するcglibにパッケージ化されています。これが、インストルメンテーションテスト以外でのMockito/Junitの動作です。しかし、AndroidインスツルメンテーションテストでMockitoを実行しようとしている場合、Bytecodeモックでは不十分であり、MockitoがART/Dalvikが理解できるDexクラスローダーにロードできるモックが必要です。 Dexmakerには、Mockitoを使用して動的に切り替えてDexモックを作成できるようにするMockito「プラグイン」があります。
どのように切り替えることがわかりますか?
Dexmaker-mockito jarには、mockito-extensions/org.mockito.plugins.MockMaker
という名前の最上位フォルダーがあり、完全修飾名com.google.dexmaker.mockito.DexmakerMockMaker
が含まれています。このjarがAPKでパッケージ化されている場合、この最上位フォルダーを「クラスローダーリソース」として含めることができます。
MockitoがMockingレイヤーを抽象化するために使用するクラスは MockUtil と呼ばれ、静的に、クラスローダーでこれらのリソースをチェックして、使用するMockMakerサブクラスを決定します PluginLoader 。 dexmaker-mockitoのリソースが見つかった場合、com.google.dexmaker.mockito.DexmakerMockMaker
がインスタンス化されてMockMakerとして使用されますが、見つからない場合、MockitoはAndroidのDVM内で互換性のないCGLibを使用します。
問題
APKの構築方法によっては、そのクラスローダーリソースを削除し、Mockitoが動的にDexmakerの使用に切り替わらないようにすることができます。
修正
まず、dexmakerが必要とするjarファイルを含めます。mockito1.9.5 +、junit、dexmaker-mockito 1.0 +、dexmaker 1.0+を使用し、MockMaker Mockitoが手動で使用するものを単に反射的に切り替えます。これが安全なのは、これがDVMで実行されている場合、デフォルトのCGLib MockMakerを使用しても、Bytecodeモックが生成されるため機能しないという事実を考えるとです。
static {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
Enumeration<URL> resources = loader.getResources("mockito-extensions/org.mockito.plugins.MockMaker");
if (resources == null || !resources.hasMoreElements()) {
LOGGER.info("Replacing Mockito mockMaker because the classloader resources were not present.");
Field field = MockUtil.class.getDeclaredField("mockMaker");
Class<?> pluginClass = loader.loadClass("com.google.dexmaker.mockito.DexmakerMockMaker");
Object plugin = pluginClass.newInstance();
field.setAccessible(true);
field.set(null, plugin);
} else {
LOGGER.info("Mockito class loader resources present");
}
} catch (Throwable e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
throw new AssertionError("Unable to replace mockMaker to be the DexmakerMockMaker", e);
} else {
e.printStackTrace();
throw new AssertionError("Unable to replace mockMaker to be the DexmakerMockMaker");
}
}
}
dexmakerは、Dexモックを出力する場所を知る必要があるため、これも必ず追加してください。
System.setProperty("dexmaker.dexcache", "/sdcard/");
EasyMockでも同じエラーが発生し、最終的にはdexmakerが存在しないことを突き止めました。私は次の依存関係でそれを解決しました:
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
それはmockitoでもうまくいくかもしれません
User23の答えは、私にとってうまくいった解決策に近いものです。
公式ドキュメント によると、AndroidアプリでMockitoを有効にするには次のことを行う必要があります。
Build.gradleに次の依存関係を追加します。
_androidTestCompile "org.mockito:mockito-core:1.10.19"
_androidTestCompile fileTree(dir: 'libs', include: ['dexmaker-1.4.jar'])
androidTestCompile fileTree(dir: 'libs', include: ['dexmaker-mockito-1.4.jar'])