web-dev-qa-db-fra.com

Tenter de se moquer de n'importe quelle classe génère ExceptionInInitializerError

Lorsque j'exécute le code suivant:

public class ActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
    ....
    public void testCanCreateMockito() {
        List mockedList = Mockito.mock(List.class);
    }
}

J'obtiens les exceptions suivantes:

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

Cela se produit avec n'importe quelle classe, List n'était qu'un exemple simple. Mes dépendances gradle sont:

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

J'ai amélioré Gradle à 1.1, essayé d'utiliser la fonction de test unitaire expérimental et non, rien ne semble faire de différence. Que se passe-t-il?

31
Aceso Under Glass

J'ai reçu cette erreur lorsque je manquais les deux dépendances dexmaker.

L'ajout de ces lignes au fichier app/gradle.build fonctionne pour moi.

androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'

J'utilise également Android Studio et j'ai trouvé que c'était une bonne idée de redémarrer AS après avoir modifié les dépendances.

90
user23

Pour moi, cela a finalement fonctionné:

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"
10
Jürgen Jatzkowski

J'obtenais cela parce que j'utilisais proguard pour mes versions de débogage à cause de la limite de la méthode 65K (Oui, j'ai besoin de réduire le nombre de dépendances), et cela provoquait cette erreur pour moi.

J'ai ajouté ceci dans ma configuration de débogage (debug) pour le résoudre:

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

Je ne sais pas si j'ai vraiment besoin de ces quatre lignes, mais cela a fait l'affaire.

3
Ciske Boekelo

REGARDEZ ICI SI VOUS NE CONSTRUISEZ PAS VOS APKS AVEC GRADLE !!!!

Si vous ne créez pas votre application à l'aide de gradle (ce qui, malheureusement, mon équipe ne le fait pas), les solutions ci-dessus peuvent ne pas fonctionner pour vous. Permettez-moi d'expliquer un peu plus sur le fonctionnement de dexmaker-mockito avant de donner la solution au problème.

Motivation

Mockito est un framework de mocking pour Java et est livré avec cglib qui crée des mocks Bytecode, c'est ainsi que Mockito/Junit en dehors des tests d'Instrumentation fonctionne. Mais si vous essayez d'exécuter Mockito dans des tests d'instrumentation Android, les simulations de Bytecode ne sont pas suffisantes et vous avez besoin de simulations que Mockito peut charger dans le chargeur de classe Dex que ART/Dalvik peut comprendre et c'est là que Dexmaker intervient. Dexmaker a un "plugin" Mockito qui permet à Mockito de passer dynamiquement à son utilisation pour créer des mock Dex.

Comment sait-il commuter?

Le pot dexmaker-mockito possède un dossier de niveau supérieur nommé mockito-extensions/org.mockito.plugins.MockMaker Contenant un nom complet com.google.dexmaker.mockito.DexmakerMockMaker. Lorsque ce bocal est fourni avec un fichier APK, ce dossier de niveau supérieur peut être inclus en tant que "ressource de chargeur de classe".

La classe que Mockito utilise pour abstraire la couche Mocking est appelée MockUtil et, statiquement, elle détermine la sous-classe MockMaker qu'elle doit utiliser en vérifiant ces ressources dans le chargeur de classe à partir de laquelle elle est lancée via son PluginLoader . Si la ressource de dexmaker-mockito peut être trouvée, alors com.google.dexmaker.mockito.DexmakerMockMaker Est instancié et utilisé comme MockMaker mais, si ce n'est pas le cas, Mockito utilise par défaut CGLib qui est incompatible avec le DVM d'Android.

Problème

Selon la façon dont vous créez votre fichier APK, vous pouvez potentiellement supprimer cette ressource de chargeur de classe et empêcher Mockito de passer dynamiquement à l'utilisation de Dexmaker.

Correction

Tout d'abord, incluez les bocaux requis par dexmaker: mockito 1.9.5+, junit, dexmaker-mockito 1.0+ et dexmaker 1.0+, puis changez simplement de manière réfléchie quel MockMaker Mockito utilisera manuellement. Ceci est sûr, étant donné que si cela s'exécute dans le DVM, l'utilisation du CGLib MockMaker par défaut ne fonctionnera jamais car il produit des mocks 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");
        }
    }
}

et assurez-vous de l'ajouter également, car dexmaker devra savoir où sortir ses simulateurs Dex.

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

mockito-extensions/org.mockito.plugins.MockMaker

J'ai rencontré la même erreur avec EasyMock et je l'ai finalement attribuée à l'absence de dexmaker. Je l'ai résolu avec la dépendance suivante:

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

Cela pourrait aussi fonctionner pour mockito

1
Aceso Under Glass

La réponse de User23 est proche de la solution qui a fonctionné pour moi.

Selon la documentation officielle vous devez faire les choses suivantes pour activer Mockito dans votre Android Android:

  1. Téléchargez dexmaker-1.4.jar et dexmaker-mockito-1.4.jar et placez-les dans votre dossier libs.
  2. Ajoutez les dépendances suivantes dans votre 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'])

0
Alexander Pacha