2012-04-25 187 views
10

欲測試的方法,具有用於與邏輯迴路,用於在bList每個元素:的Mockito ClassCastException異常

@RunWith(MockitoJUnitRunner.class) 
class ATest { 

    @Mock 
    private B b; 

    @Mock 
    private Map<Int, List<B>> bMap; 

    @Mock(answer = Answers.RETURNS_DEEP_STUBS) 
    private List<B> bList; 

    @Spy 
    @InjectMocks 
    private C c; 
    .... 

    @Test 
    public void test(){ 

     //this line executes fine 
     when(bList.size()).thenReturn(1); 

     //strangely this works fine 
     when(bMap.get(any())).thenReturn(bList); 

     //ClassCastException 
     when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b); 

     c.methodIWantToTest(); 
    } 
} 

異常我得到:

class A { 
    void someMethod(){ 

     for(B b: bList){ 
      //some logic for b 
     } 
    } 
} 

執行以下測試時我得到一個異常是:

java.lang.ClassCastException: 
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B

有沒有人遇到過這個問題,並提出一個解決方法?

...我已經尋找一個解決方案和所遇到的一些鏈接: http://code.google.com/p/mockito/issues/detail?id=251http://code.google.com/p/mockito/issues/detail?id=107

+0

這可能是一個現有的問題,如鏈接所指出的。 – 2012-04-25 22:31:47

+2

你真的試圖嘲笑列表和地圖,或者只是爲了說明這個問題嗎?你爲什麼不使用ArrayList和HashMap實現並注入它們? – jhericks 2012-04-26 01:14:35

+0

@jhericks是的你是對的,我應該切換到使用ArrayList和HashMap實現。謝謝 – 2012-04-26 14:09:44

回答

18

由於this link you posted表明,你已經遇到了一個錯誤與Answers.RETURNS_DEEP_STUBS

我實際上沒有看到任何理由在您的示例代碼中實際使用RETURNS_DEEP_STUBS。你真的應該嘗試評估你是否需要深存根,因爲,「每次模擬回來一個模擬仙女死亡的時候」。所以如果可以的話,就把它拿出來,你的例子就可以發揮作用。

但是,如果您堅持使用深存根,您可以通過將方法調用返回值上傳到Object來解決此錯誤。例如,用您的代碼替換您的代碼中的違規行:

when((Object)bList.get(0)).thenReturn(b); 

所有這些都說了,我個人認同@jhericks。最好的解決方案可能是使用實際的ArrayList,其中包含您的模擬而不是嘲諷List。唯一的問題是讓你的列表被注入,所以你必須使用@Spy。例如:

@RunWith(MockitoJUnitRunner.class) 
class ATest{ 
    private B b = mock(B.class); 
    @Spy 
    private List<B> bList = new ArrayList<B>() {{ add(b); }}; 

    @InjectMocks 
    private C c = new C(); 

    @Test 
    public void test(){ 
    c.methodIWantToTest(); 
    // verify results 
    } 
} 
+0

我嘗試了兩種選擇,他們都工作。我看到Mockito文檔中提到的情況,並且不會使用mock來返回嘲諷。謝謝。 – 2012-04-26 14:08:28

1

其實我會搜索classpath問題和relaoding。在mockito郵件列表和問題追蹤器上,一些報告的問題可能被追蹤到不正確的類路徑(錯誤版本的jar等)和類重新加載(一些jar被重新加載,但不是mockito,然後導致實例化類錯誤的類加載器)。

@Aces你能否提供更多的細節,如版本和工具的名稱使用的是(行家,規格,萬無一失,遊戲框架,JRebel的,也許,等...)

+0

我用ArrayList和HashMap實現替換了模擬,並且按照答案中的建議嘗試了上傳。這兩個解決方案都很好。所以我不認爲項目中有任何類路徑問題。到現在爲止,我已經能夠使用mock來執行測試用例了。 – 2012-04-26 14:14:06

0

不幸的是,這不是可能

案例:對API的測試:這種用法的

interface ConfigurationBuilder {...} 
configurationBuilder.newServerAction("s1").withName("111")....create(); 

主要原因是在編譯時的兼容性維護。 但是的Mockito不能支持泛型與RETURNS_MOCKS和RETURNS_DEEP_STUBS選項由於在Java類型擦除鏈:例如在

Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1"); 
b.withName("111")...create(); 

上述結果應該是serveraction對但在它的Mockito是生成的類的對象。

請參閱Issue: Can not Return deep stubs from generic method that returns generic type #484