Попытка mockito издеваться над любым классом генерирует ExceptionInInitializerError

Когда я запускаю следующий код:

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 

Это происходит с любым классом, List был просто легким примером. Мои зависимости градиента:

 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') } 

Я повысил уровень градиента до 1,1, попробовал использовать экспериментальную единицу тестовой функции, а не, ничего, похоже, не имеет значения. Что происходит?

Solutions Collecting From Web of "Попытка mockito издеваться над любым классом генерирует ExceptionInInitializerError"

Я получил эту ошибку, когда мне не хватало две зависимости 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" 

Я получал это, потому что я использовал proguard для своих отладочных сборников из-за ограничения метода 65K (да, мне нужно сократить количество зависимостей), и это вызывало эту ошибку для меня.

Я добавил это в мою (отладочную) конфигурацию proguard, чтобы решить эту проблему:

 ### Keep Mockito -keep class org.mockito.** { *; } -keep interface org.mockito.** { *; } -keep class com.google.dexmaker.** { *; } -keep interface com.google.dexmaker.** { *; } 

Не уверен. Если мне действительно нужны все четыре из этих строк, но это сделало трюк.

Я столкнулся с той же ошибкой с EasyMock и в конечном итоге проследил ее до отсутствия dexmaker. Я решил это со следующей зависимостью:

 androidTestCompile "com.google.dexmaker:dexmaker:1.2" 

Это может работать и для мокито

СМОТРИТЕ ЗДЕСЬ, ЕСЛИ ВЫ НЕ СОЗДАВАЕТЕ ВАШИ АПКСЫ С ИСПОЛЬЗОВАНИЕМ ГРАДЛЕМ !!!!

Если вы не создаете свое приложение с помощью gradle (что, к сожалению, у моей команды нет), то вышеупомянутые решения могут не сработать для вас. Позвольте мне объяснить немного больше о том, как работает dexmaker-mockito, прежде чем дать решение проблемы.

мотивация

Mockito – издевательская структура для Java и поставляется в комплекте с cglib, который создает Bytecode mocks, так работает Mockito / Junit вне тестов Instrumentation. Но если вы пытаетесь запустить Mockito в тестах на аппаратную платформу Android, то макеты Bytecode недостаточно, и вам нужны макеты, которые Mockito может загружать в загрузчик классов Dex, который может использовать ART / Dalvik, и вот что делает Dexmaker. Dexmaker имеет плагин Mockito », Что позволяет Mockito динамически переключаться на его использование для создания Dex mocks.

Как он может переключиться?

В банке dexmaker-mockito есть папка верхнего уровня с именем mockito-extensions/org.mockito.plugins.MockMaker содержащая полное имя com.google.dexmaker.mockito.DexmakerMockMaker . Когда эта банка упакована в APK, эта папка верхнего уровня может быть включена как «ресурс загрузчика класса».

Класс, который Mockito использует для абстрагирования слоя Mocking, называется MockUtil, и статически он определяет, какой подкласс MockMaker он должен использовать, проверяя эти ресурсы в загрузчике классов, которые он запускает с помощью своего PluginLoader . Если ресурс dexmaker-mockito можно найти, то com.google.dexmaker.mockito.DexmakerMockMaker создается и используется как MockMaker, но если это не так, Mockito по умолчанию использует CGLib, который несовместим с DVM Android.

проблема

В зависимости от того, как вы создаете APK, вы можете разделить ресурс загрузчика этого класса и заставить Mockito не динамически переключаться на использование Dexmaker.

исправлять

Во-первых, включите банки, которые требует dexmaker: mockito 1.9.5+, junit, dexmaker-mockito 1.0+ и dexmaker 1.0+, а затем просто рефлексивно переключите, какой MockMaker Mockito будет использовать вручную. Это безопасно, учитывая тот факт, что если это работает в DVM, использование CGLib по умолчанию CKLib MockMaker никогда не будет работать, так как он создает Bytecode mocks.

 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 mocks.

 System.setProperty("dexmaker.dexcache", "/sdcard/"); 

Mockito-расширение / org.mockito.plugins.MockMaker

Ответ User23 близок к решению, которое сработало для меня.

Согласно официальной документации, вы должны сделать следующее, чтобы активировать Mockito в своем приложении для Android:

  1. Загрузите dexmaker-1.4.jar и dexmaker-mockito-1.4.jar и поместите их в папку libs.
  2. Добавьте в свой файл 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'])