Ho iniziato a colpire uno strano ClassCastException in Mockito quando lo si utilizza con Robolectric. Quando eseguo gli stessi test non usando il runner Robolectric, tutto va bene, non viene lanciata alcuna eccezione.Mockito con Robolectric: "ClassCastException si è verificato durante la creazione del proxy"
Ecco traccia dello stack:
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
Il codice che sto utilizzando è il seguente:
@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);
}
...
}
Questo è il modo Robolectric corridore assomiglia:
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;
}
};
}
}
Che cosa dovrebbe Ho risolto per sbarazzarmi di questa eccezione?
Interessante! Ho appena indovinato qualcosa in conflitto con Kotlin/Robolectric. Kotlin sostituisce ClassLoader? Spero che gli esperti di Kotlin si uniscano alla conversazione –
Puoi controllare la soluzione da qui https://github.com/robolectric/robolectric-gradle-plugin/issues/75 –
@EugenMartynov buon punto, ho aggiunto il tag "kotlin", forse Kotlin ragazzi aiuterebbero. –