2013-04-11 79 views
40

我正在使用mockito 1.9.5。 我有以下代碼:嘲笑一種使用mockito返回泛型與通配符的方法

public class ClassA { 

public List<? extends MyInterface> getMyInterfaces() { 
    return null; 
} 

public static void testMock() { 
    List<MyInterface> interfaces = new ArrayList<>(); 
    ClassA classAMock = mock(ClassA.class); 
    when(classAMock.getMyInterfaces()).thenReturn(interfaces);  
} 

我得到了thenReturn(interfaces)編譯錯誤說:

"The method thenReturn(List<capture#1-of ? extends MyInterface>) in the type 
OngoingStubbing<List<capture#1-of ? extends MyInterface>> is not applicable for the arguments 
(List<MyInterface>)" 

然而,當我使用的的Mockito的thenAnswer方法,我沒有得到這個錯誤。誰能告訴我發生了什麼事?爲什麼我在使用thenReturn方法時遇到錯誤? 當第三方提供ClassA並且無法修改時,是否有任何其他方法可以解決此問題?

+0

您不應在'getMyInterfaces'的返回類型中使用通配符。這不是一個好習慣,因爲那個API的客戶必須處理一個他們不知道的通配符。 – SpaceTrucker 2013-04-11 07:35:26

+1

我不控制這個API。它由第三方提供。 – user1504992 2013-04-11 07:59:46

+5

@SpaceTrucker我認爲有一個返回類型像「List <?擴展MyInterface>'是一件非常明智的事情。這意味着你(作爲方法調用者)可以將'MyInterface'對象從列表中取出,但不能在其中放入任何東西。 – 2014-11-17 10:13:12

回答

49

編輯:從Mockito 1.10.x開始,嵌入類中的泛型類型現在被Mockito用於深存根。即。

public interface A<T extends Observer & Comparable<? super T>> { 
    List<? extends B> bList(); 
    T observer(); 
} 

B b = deep_stubbed.bList().iterator().next(); // returns a mock of B ; mockito remebers that A returns a List of B 
Observer o = deep_stubbed.observer(); // mockito can find that T super type is Observer 
Comparable<? super T> c = deep_stubbed.observer(); // or that T implements Comparable 

嘗試的Mockito其所能得到的類型信息,編譯器嵌入,但是當擦除應用,可以的Mockito不能做任何事情,但返回的Object一個模擬。


原始:嗯,這是與仿製藥比更多的Mockito的一個問題。對於仿製藥,你應該閱讀什麼Angelika Langer寫在他們身上。對於當前話題,即通配符,請閱讀section

但總之,你可以使用是的Mockito的其他語法來幫助你目前的情況:

doReturn(interfaces).when(classAMock).getMyInterfaces(); 

或者與BDD別名:

willReturn(interfaces).given(classAMock).getMyInterfaces(); 

然而,你可以寫更普遍友好的包裝。這將有助於未來的開發者使用相同的第三方API。


作爲一個方面說明:你不應該嘲笑類型,你不擁有,它可以導致許多錯誤和問題。相反,你應該有一些包裝。例如DAO和存儲庫代表了這樣的想法,人們會模擬DAO或存儲庫接口,而不是JDBC/JPA/Hibernate的東西。有許多博客文章有關:

+0

也感謝有見識的鏈接! – thSoft 2013-10-01 15:02:27

+0

雖然doReturn語法不是類型安全的(但可以返回任何東西,而不僅僅是一些東西)。 (雖然在這個設置過程中你仍然會得到一個例外 - 但是如果你輸入了一個不同類型的列表則不會。) – 2014-11-17 10:36:21

+0

@PaŭloEbermann事實上,這是由於類型擦除。在這種情況下,檢查在運行時完成。另一種形式可以在編譯時進行類型檢查。 – Brice 2014-11-17 12:55:02

36

另一種解決方案(儘管不那麼可讀)是合格的靜態方法調用when綁定通配符:

Mockito.<List<? extends MyInterface>>when(classAMock.getMyInterfaces()).thenReturn(interfaces); 
+8

這是黑魔法,但它完美的作品。謝謝 – 2015-01-15 07:35:49

+0

這是唯一爲我工作的人。 – gladed 2017-05-31 23:18:40