与Robolectric的Mockito:“创建代理时发生ClassCastException”

在Robolectric中使用它时,我开始在Mockito中碰到一个奇怪的ClassCastException。 当我运行相同的测试不使用Robolectric转轮,一切顺利,没有例外抛出。

这里是堆栈跟踪:

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 

我正在使用的代码如下所示:

 @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); } ... } 

这就是Robolectric跑步者的样子:

 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; } }; } } 

我应该修复什么来摆脱这个异常?

如所建议的

'禁用对象缓存可能有助于'

你可以创建覆盖MockitoConfiguration。
这样做

  • 在src / test / java下创建一个名为org.mockito.configuration的包
  • 编写MockitoConfiguration类

类文件

 package org.mockito.configuration; public class MockitoConfiguration extends DefaultMockitoConfiguration { @Override public boolean enableClassCache() { return false; } } 

尝试再次构建您的代码。

这实际上不是Kotlin问题,而是Robolectric / Mockito。 我相信这与类加载器有关。 如果用任何其他库接口(JDK或您的项目类)来替换Kotlin类,您将看到相同的异常。 不幸的是我看不到解决方案,因为我不明白Robolectric内部。 你最好问Robolectric或Mockito团队。

我有类似的问题。 基本上,你有一些课程,你想Mockito模拟和其他类,你想要PowerMock嘲笑。 我通过将@PowerMockIngore注释添加到我的测试类并指定我想用常规“ol mockito”模拟的类来解决此问题。 所以在你的情况下,我想添加注释:

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

会工作。

解决方法谨慎!

请您自己承担风险使用。

首先你必须重新定义kotlin函数接口:

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

嘲笑它:

 val onUpdate: TestFunction0<Unit> = mock() 

我知道问题是有点老,但它可能会帮助别人寻找答案。

添加

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

 @RunWith(ApplicationTestRunner.class) 

应该解决这个问题。