
[英]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.