![](/img/trans.png)
[英]Mockito spy: Trying to use doReturn in spy class method but is using original method
[英]Mockito: Trying to spy on method is calling the original method
我正在使用 Mockito 1.9.0。 我想在 JUnit 測試中模擬一個類的單個方法的行為,所以我有
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
問題是,在第二行中,實際上調用了myClassSpy.method1()
,從而導致異常。 我使用模擬的唯一原因是以后,無論何時myClassSpy.method1()
,都不會調用真正的方法,並且將返回myResults
對象。
MyClass
是一個接口,而myInstance
是它的一個實現,如果這很重要的話。
我需要做什么來糾正這種間諜行為?
讓我引用官方文檔:
監視真實物體的重要問題!
有時不可能將 when(Object) 用於 stubbing 間諜。 例子:
List list = new LinkedList(); List spy = spy(list); // Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty) when(spy.get(0)).thenReturn("foo"); // You have to use doReturn() for stubbing doReturn("foo").when(spy).get(0);
在您的情況下,它類似於:
doReturn(resultsIWant).when(myClassSpy).method1();
就我而言,使用 Mockito 2.0,我必須將所有any()
參數更改為nullable()
以便存根真正的調用。
我的情況與接受的答案不同。 我試圖為不在該包中的實例模擬包私有方法
package common;
public class Animal {
void packageProtected();
}
package instances;
class Dog extends Animal { }
和測試類
package common;
public abstract class AnimalTest<T extends Animal> {
@Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
@Test
public void myTest(){}
}
編譯是正確的,但是當它嘗試設置測試時,它會調用真正的方法。
聲明方法protected或public 可以解決問題,但這不是一個干凈的解決方案。
Tomasz Nurkiewicz 的回答似乎並沒有說明全部!
NB Mockito 版本:1.10.19。
我非常喜歡 Mockito 新手,所以無法解釋以下行為:如果有專家可以改進這個答案,請隨意。
有問題的方法在這里, getContentStringValue
,是不是final
和不是static
。
這一行確實調用了原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
這一行沒有調用原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
由於我無法回答的原因,使用isA()
會導致doReturn
的預期(?)“不調用方法”行為失敗。
我們來看看這里涉及的方法簽名:它們都是Matchers
static
方法。 Javadoc 說兩者都返回null
,這本身有點難以理解。 據推測,作為參數傳遞的Class
對象被檢查,但結果要么從未計算過,要么被丟棄。 鑒於null
可以代表任何類,並且您希望模擬方法不被調用, isA( ... )
和any( ... )
的簽名不能只返回null
而不是泛型參數* <T>
?
反正:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
API 文檔對此沒有提供任何線索。 似乎也說需要這種“不調用方法”行為是“非常罕見的”。 我個人使用這種技術的所有時間:通常我發現嘲諷涉及的幾行其中“設置場景” ......隨后調用,然后將你所上演的模擬情境“中扮演了”現場的方法.. . . 當您設置布景和道具時,您最不希望演員進入舞台左側並開始表演他們的心...
但這遠遠超出了我的工資等級......我請任何路過的 Mockito 大祭司解釋......
*“通用參數”是正確的術語嗎?
另一種可能導致 spies 出現問題的情況是,當您測試spring bean (使用 spring 測試框架)或其他一些在 test 期間代理對象的框架時。
例子
@Autowired
private MonitoringDocumentsRepository repository
void test(){
repository = Mockito.spy(repository)
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
在上面的代碼中,Spring 和 Mockito 都會嘗試代理您的 MonitoringDocumentsRepository 對象,但 Spring 將是第一個,這將導致真正調用 findMonitoringDocuments 方法。 如果我們在將間諜放在存儲庫對象上之后立即調試我們的代碼,它將在調試器中看起來像這樣:
repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$
@SpyBean 來救援
如果我們使用@SpyBean
批注代替@Autowired
批注,我們將解決上述問題,SpyBean 批注也將注入存儲庫對象,但它將首先由 Mockito 代理,並且在調試器中看起來像這樣
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
這是代碼:
@SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
我發現 spy 調用原始方法的另一個原因。
有人想模擬final
堂課,並發現了MockMaker
:
由於這與我們當前的機制不同,並且這個機制有不同的限制,並且我們想要收集經驗和用戶反饋,因此必須明確激活此功能才能使用; 它可以通過 mockito 擴展機制通過創建文件
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
其中包含一行:mock-maker-inline
來源: https : //github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
在我合並並將該文件帶到我的機器后,我的測試失敗了。
我只需要刪除該行(或文件),然后spy()
工作了。
確保類中的方法不被調用的一種方法是使用虛擬方法覆蓋該方法。
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
@Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
給scala用戶的答案:即使將doReturn
放在首位也不起作用! 看到這篇文章 。
正如一些評論中提到的,我的方法是“靜態的”(盡管被類的實例調用)
public class A {
static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static
解決方法是創建一個實例方法或使用一些配置將 Mockito 升級到更新版本: https ://stackoverflow.com/a/62860455/32453
監視真實物體的重要問題
當使用 spies 存根方法時,請使用doReturn()系列方法。
when(Object)將導致調用可能引發異常的實際方法。
List spy = spy(new LinkedList());
//Incorrect , spy.get() will throw IndexOutOfBoundsException
when(spy.get(0)).thenReturn("foo");
//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
聚會有點晚,但以上解決方案對我不起作用,所以分享我的 0.02$
Mokcito 版本:1.10.19
我的類
private int handleAction(List<String> argList, String action)
測試.java
MyClass spy = PowerMockito.spy(new MyClass());
1.
doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());
2.
doReturn(0).when(spy , "handleAction", any(), anyString());
3.
doReturn(0).when(spy , "handleAction", null, null);
doReturn(0).when(spy , "handleAction", any(List.class), anyString());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.