简体   繁体   English

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

[英]Mockito with Robolectric: “ClassCastException occurred when creating the proxy”

I've started hitting a strange ClassCastException in Mockito when using it with Robolectric. 当与Robolectric一起使用时,我开始在Mockito中遇到一个奇怪的ClassCastException。 When I run the same tests not using Robolectric runner, everything goes fine, no exception is thrown. 当我运行不使用Robolectric跑步者的相同测试时,一切都很顺利,没有抛出任何异常。

Here is 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

The code I'm using is as follows: 我正在使用的代码如下:

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

    ...
}

This is how Robolectric runner looks like: 这就是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;
            }
        };
    }
}

What should I fix to get rid of this exception? 我应该解决什么来摆脱这个例外?

As suggested 如建议

'disabling the Objenesis cache might help' '禁用Objenesis缓存可能会有所帮助'

You can create override MockitoConfiguration. 您可以创建覆盖MockitoConfiguration。
To do so 这样做

  • Create a package named org.mockito.configuration under your src/test/java 在src / test / java下创建一个名为org.mockito.configuration的包
  • Write the MockitoConfiguration class 编写MockitoConfiguration类

Class File 类文件

package org.mockito.configuration;

public class MockitoConfiguration extends DefaultMockitoConfiguration {

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

Try to build your code again. 尝试再次构建代码。

I know question is bit old, but it may help someone looking for the answer. 我知道问题有点老,但它可能有助于寻找答案的人。

Adding 添加

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

After

@RunWith(ApplicationTestRunner.class)

Should solve the issue. 应该解决这个问题。

This is actually not Kotlin issue but Robolectric/Mockito. 这实际上不是Kotlin问题,而是Robolectric / Mockito。 I believe it is related to classloaders. 我相信它与类加载器有关。 If you replace Kotlin class with any other library interface (neither JDK nor your project's class) you will see the same exception. 如果将Kotlin类替换为任何其他库接口(既不是JDK也不是项目的类),您将看到相同的异常。 Unfortunately I see no solution as I don't understand Robolectric internals. 不幸的是,由于我不了解Robolectric内部,我认为没有解决方案。 You better to ask Robolectric or Mockito teams about this. 你最好向Robolectric或Mockito团队询问此事。

I've had a similar problem. 我有类似的问题。 Basically, you've got some classes that you want Mockito mock and other classes that you want PowerMock to mock. 基本上,你有一些你想要Mockito模拟的课程以及你希望PowerMock模拟的其他课程。 I solved it by adding the @PowerMockIngore annotation to my test class and specifying the classes that I wanted to mock using regular 'ol mockito. 我通过将@PowerMockIngore注释添加到我的测试类并使用常规'ol mockito指定我想要模拟的类来解决它。 So in your case, I think adding the annotation: 所以在你的情况下,我认为添加注释:

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

would work. 会工作。

Workaround caution! 解决方法谨慎!

Please use at your own risk. 请您自担风险使用。

First you have to redefine kotlin function interfaces: 首先,您必须重新定义kotlin函数接口:

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

And mock it: 嘲笑它:

val onUpdate: TestFunction0<Unit> = mock()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM