2015-03-16 17 views
6

Tôi đã bắt đầu đánh một ClassCastException lạ trong Mockito khi sử dụng nó với Robolectric. Khi tôi chạy các bài kiểm tra tương tự không sử dụng Á hậu Robolectric, mọi thứ diễn ra tốt đẹp, không có ngoại lệ nào được ném ra.Mockito với Robolectric: "ClassCastException xảy ra khi tạo proxy"

Đây là 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 

Mã Tôi đang sử dụng như sau:

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

    ... 
} 

Đây là cách Robolectric Á hậu trông giống như:

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

gì nên Tôi sửa chữa để loại bỏ ngoại lệ này?

+0

Thú vị! Tôi đã đoán rằng có điều gì đó mâu thuẫn với Kotlin/Robolectric. Kotlin có thay thế ClassLoader không? Tôi hy vọng các chuyên gia Kotlin sẽ tham gia cuộc nói chuyện –

+0

bạn có thể kiểm tra giải pháp từ đây https://github.com/robolectric/robolectric-gradle-plugin/issues/75 –

+0

@EugenMartynov điểm tốt, tôi đã thêm "Kotlin" tag, có lẽ Kotlin mọi người sẽ giúp. –

Trả lời

1

Đây thực sự không phải là vấn đề Kotlin mà là Robolectric/Mockito. Tôi tin rằng nó có liên quan đến classloaders. Nếu bạn thay thế lớp Kotlin bằng bất kỳ giao diện thư viện nào khác (cả JDK lẫn lớp dự án của bạn), bạn sẽ thấy cùng một ngoại lệ. Thật không may tôi thấy không có giải pháp như tôi không hiểu Robolectric internals. Bạn nên hỏi đội Robolectric hoặc Mockito về việc này.

+0

OK, Sergey, cảm ơn bạn đã làm rõ. –

+0

Tôi đang sử dụng 'mockito' với' robolectric' mà không có bất kỳ vấn đề gì. Mã tương tự hoạt động tốt cho tôi. Có phiên bản cụ thể của 'robolectric' và' mockito' không? –

+0

Có vẻ như vậy. Tôi phát hiện ra rằng vấn đề là gây ra các trình nạp lớp khác nhau được sử dụng bởi trình kiểm tra (Trình khởi chạy/AsmInstrumentingClassLoader) và trình nạp lớp của mockito (SearchingClassLoader) để lớp sơ khai được tạo ra thông qua một lớp Proxy nhưng chúng được nạp bởi một lớp khác. Nó đòi hỏi điều tra nhiều hơn và tôi khá chắc chắn đội Mockito hoặc Robolectric có thể làm tốt hơn. –

1

Tôi đã gặp sự cố tương tự. Về cơ bản, bạn có một số lớp mà bạn muốn Mockito giả lập và các lớp khác mà bạn muốn PowerMock giả lập. Tôi đã giải quyết nó bằng cách thêm chú thích @PowerMockIngore vào lớp thử nghiệm của tôi và chỉ định các lớp mà tôi muốn giả lập bằng cách sử dụng 'mockito' thông thường. Vì vậy, trong trường hợp của bạn, tôi nghĩ rằng việc thêm chú thích:

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

sẽ hoạt động.

1

Cảnh báo cẩn thận!

Vui lòng tự chịu rủi ro.

Trước tiên, bạn phải xác định lại Kotlin chức năng giao diện:

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

Và chế nhạo nó:

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

Như đã đề cập

'vô hiệu hóa bộ nhớ cache Objenesis sức giúp đỡ'

Bạn có thể tạo ghi đè MockitoConfiguration.
Để làm như vậy

  • Tạo một gói có tên org.mockito.configuration dưới src/thử nghiệm của bạn/java
  • Viết lớp MockitoConfiguration

Lớp tập tin

package org.mockito.configuration; 

public class MockitoConfiguration extends DefaultMockitoConfiguration { 

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

Hãy thử tạo lại mã của bạn.

0

Tôi biết câu hỏi là hơi cũ, nhưng nó có thể giúp ai đó tìm kiếm câu trả lời.

Thêm

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

Sau

@RunWith(ApplicationTestRunner.class) 

nên giải quyết vấn đề này.

Các vấn đề liên quan