2015-03-16 10 views
6

Ich habe angefangen, eine seltsame ClassCastException in Mockito zu treffen, wenn ich es mit Robolectric verwende. Wenn ich dieselben Tests ohne Robolectric Runner durchführe, läuft alles gut, es wird keine Ausnahme geworfen. HierMockito mit Robolectric: "ClassCastException trat beim Erstellen des Proxys auf"

ist Stack-Trace:

org.mockito.exceptions.base.MockitoException: 
ClassCastException occurred when creating the proxy. 
You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration) 
    at com.compassrosetech.ccs.android.test.ObservableCacheDispatcherTest.setUp(ObservableCacheDispatcherTest.java:63) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) 
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:158) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 
Caused by: java.lang.ClassCastException: kotlin.Function0$$EnhancerByMockitoWithCGLIB$$c0163e7f cannot be cast to org.mockito.cglib.proxy.Factory 
    at org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(ClassImposterizer.java:128) 
    at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:63) 
    at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56) 
    at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23) 
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26) 
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51) 
    at org.mockito.Mockito.mock(Mockito.java:1243) 
    at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:30) 
    at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16) 
    at org.mockito.internal.configuration.DefaultAnnotationEngine.createMockFor(DefaultAnnotationEngine.java:43) 
    at org.mockito.internal.configuration.DefaultAnnotationEngine.process(DefaultAnnotationEngine.java:66) 
    at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:71) 
    at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:55) 
    at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:108) 
    ... 29 more 

Der Code, den ich verwende, ist wie folgt:

@RunWith(ApplicationTestRunner.class) 
public class ObservableCacheDispatcherTest { 

    @Mock 
    private IDataMapper mockDataMapper; 

    @Mock 
    private ICache mockCache; 

    @Mock 
    private Function0<Object> mockLoader; 

    private ObservableCacheDispatcher cacheDispatcher; 


    @Before 
    public void setUp() { 
     MockitoAnnotations.initMocks(this); // <-- exception happens when executing this statement 
     cacheDispatcher = new ObservableCacheDispatcher(mockCache, mockDataMapper); 
    } 

    ... 
} 

Dies ist, wie Robolectric Läufer wie folgt aussehen:

public class ApplicationTestRunner extends RobolectricTestRunner { 

    //Maximun SDK Robolectric will compile (issues with SDK > 18) 
    private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18; 

    private static final String ANDROID_MANIFEST_PATH = "../app/src/main/AndroidManifest.xml"; 
    private static final String ANDROID_MANIFEST_RES_PATH = "../app/src/main/res"; 

    /** 
    * Call this constructor to specify the location of resources and AndroidManifest.xml. 
    * 
    * @throws org.junit.runners.model.InitializationError 
    */ 
    public ApplicationTestRunner(Class<?> testClass) throws InitializationError { 
     super(testClass); 
    } 

    @Override protected AndroidManifest getAppManifest(Config config) { 
     return new AndroidManifest(Fs.fileFromPath(ANDROID_MANIFEST_PATH), 
       Fs.fileFromPath(ANDROID_MANIFEST_RES_PATH)) { 
      @Override 
      public int getTargetSdkVersion() { 
       return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC; 
      } 
     }; 
    } 
} 

Was sollte Ich repariere, um diese Ausnahme loszuwerden?

+0

Interessant! Ich vermute nur, dass etwas mit Kotlin/Robolectric kollidiert. Ersetzt Kotlin ClassLoader? Ich hoffe, Kotlin Experten werden beitreten Konversation –

+0

Können Sie die Lösung von hier https://github.com/robolectric/robolectric-gradel-plugin/issues/75 –

+0

@EugenMartynov guter Punkt, habe ich "Kotlin" -Tag, vielleicht Kotlin hinzugefügt Jungs würden helfen. –

Antwort

1

Dies ist eigentlich nicht Kotlin Ausgabe aber Robolectric/Mockito. Ich glaube, dass es mit Klassenladern zu tun hat. Wenn Sie die Kotlin-Klasse durch eine andere Bibliotheksschnittstelle ersetzen (weder JDK noch die Klasse Ihres Projekts), sehen Sie dieselbe Ausnahme. Leider sehe ich keine Lösung, da ich Robolectric Internals nicht verstehe. Fragen Sie lieber Robolectric oder Mockito Teams.

+0

Verstanden, Sergey, danke für die Klarstellung. –

+0

Ich benutze 'mockito' mit' robolectric' ohne irgendein Problem. Ein ähnlicher Code funktioniert gut für mich. Ist es eine spezifische Version von 'robolectric' und' mockito'? –

+0

Scheint so zu sein. Ich entdeckte, dass das Problem verschiedene Klassenladeprogramme verursacht, die von Test Runner (Launcher/AsmInstrumentingClassLoader) und Mockitos Classloader (SearchingClassLoader) verwendet werden, sodass die Stub-Klasse über eine generiert wird, aber die Proxy-Klasse (von der wir versucht haben) wurde von einer anderen geladen. Es erfordert mehr Nachforschungen und ich bin mir ziemlich sicher, dass Mockito oder Robolectric Teams es besser machen können. –

1

Ich hatte ein ähnliches Problem. Im Grunde genommen gibt es einige Klassen, die Mockito-Mock und andere Klassen, die PowerMock nachahmen soll. Ich löste es, indem ich die @PowerMockIngore Annotation meiner Testklasse hinzufügte und die Klassen spezifizierte, die ich mit regelmäßigem 'ol mockito verspotten wollte. Also in Ihrem Fall, ich denke, die Anmerkung hinzufügen:

@PowerMockIgnore({"com.package.IDataMapper", "com.package.ICache" ..etc}) 

würde funktionieren.

1

Umgehung Vorsicht!

Bitte verwenden Sie auf eigene Gefahr.

Zuerst müssen Sie Kotlin Funktionsschnittstellen neu zu definieren: es

interface TestFunction0<R> : Function0<R> 
interface TestFunction1<T1, R> : Function1<T1, R> 

und Mock:

val onUpdate: TestFunction0<Unit> = mock() 
7

Als

vorgeschlagen

'Macht helfen, den Objenesis Cache deaktivieren'

Sie können MockitoConfiguration überschreiben.
Dazu

  • ein Paket org.mockito.configuration unter Ihrem src/test/java
  • schreiben

Klasse Datei die MockitoConfiguration Klasse mit dem Namen erstellen

package org.mockito.configuration; 

public class MockitoConfiguration extends DefaultMockitoConfiguration { 

    @Override 
    public boolean enableClassCache() { 
    return false; 
    } 
} 

Versuchen Sie, Ihren Code erneut zu erstellen.

0

Ich weiß, Frage ist ein bisschen alt, aber es kann jemand auf der Suche nach der Antwort helfen.

Hinzufügen

@PowerMockIgnore({ "org.mockito.*"}) 

Nach

@RunWith(ApplicationTestRunner.class) 

Sollte das Problem lösen.

Verwandte Themen