Java Mockito:试图监视方法正在调用原始方法
我正在使用Mockito 1.9.0。我希望在JUnit测试中模拟类的单个方法的行为,因此Java Mockito:试图监视方法正在调用原始方法,java,junit,mockito,Java,Junit,Mockito,我正在使用Mockito 1.9.0。我希望在JUnit测试中模拟类的单个方法的行为,因此 final MyClass myClassSpy = Mockito.spy(myInstance); Mockito.when(myClassSpy.method1()).thenReturn(myResults); 问题是,在第二行中,myClassSpy.method1()实际上被调用,导致异常。我使用mock的唯一原因是,以后无论何时调用myClassSpy.method1(),都不会调用真正的
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
问题是,在第二行中,myClassSpy.method1()
实际上被调用,导致异常。我使用mock的唯一原因是,以后无论何时调用myClassSpy.method1()
,都不会调用真正的方法,并且会返回myResults
对象
MyClass
是一个接口,myInstance
是该接口的一个实现,如果这很重要的话
我需要做些什么来纠正这种间谍行为?让我引用一下:
重要的是,我已经掌握了监视真实物体的方法!
有时,当(对象)用于刺杀间谍时,是不可能的。例如:
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();
我的情况与公认的答案不同。我试图为一个不在包中的实例模拟包私有方法
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(){}
}
包通用;
公共抽象类动物测试{
@以前
设置(){
doNothing().when(getInstance()).packageProtected();
}
抽象T getInstance();
}
包实例;
类DogTest扩展了AnimalTest{
Dog getInstance(){
返回间谍(新狗());
}
@试验
public void myTest(){}
}
编译是正确的,但是当它试图设置测试时,它会调用real方法
宣布该方法受保护或公开解决了这个问题,尽管这不是一个干净的解决方案。托马兹·努尔基维茨的回答似乎并没有说明全部情况强> NB Mockito版本:1.10.19 我是一个莫基托新手,所以无法解释以下行为:如果有专家可以改进这个答案,请放心 这里讨论的方法,
getContentStringValue
,是非最终
和非静态
此行调用原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
此行不调用原始方法getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
出于我无法回答的原因,使用isA()
会导致doReturn
的预期(?“不要调用方法”行为失败
让我们看看这里涉及的方法签名:它们都是匹配器的静态方法。Javadoc说这两个函数都返回null
,这本身就有点难理解。假定检查作为参数传递的类
对象,但结果从未计算或丢弃。鉴于null
可以代表任何类,并且您希望模拟方法不会被调用,那么isA(…)
和any(…)
的签名不能只返回null
而不是泛型参数*
无论如何:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
publicstatictisa(java.lang.Class clazz)
公共静态T any(java.lang.Class clazz)
API文档没有给出任何关于这方面的线索。它似乎还说,这种“不调用方法”行为的必要性“非常罕见”。就我个人而言,我一直都在使用这种技巧:我发现模仿通常包括几句“设置场景”的台词。。。然后调用一个方法,该方法将“播放”已上演的模拟上下文中的场景。。。当你在设置布景和道具的时候,你最不想看到的就是演员们从左边进入舞台,开始表演他们的心
但这远远超出了我的工资等级。。。我请任何路过的莫基托大祭司解释
*“泛型参数”是正确的术语吗?在我的例子中,使用Mockito 2.0,我不得不将所有any()
参数更改为nullable()
,以便存根真正的调用。我发现了spy调用原始方法的另一个原因
有人想模拟一个final
类,并找到了关于MockMaker
:
由于这与我们当前的机制不同,并且这一机制有不同的限制,并且我们希望收集经验和用户反馈,因此必须明确激活此功能才能使用;可以通过mockito扩展机制创建文件src/test/resources/mockito extensions/org.mockito.plugins.MockMaker
,其中包含一行:mock maker inline
资料来源:
在我合并并将该文件带到我的机器后,我的测试失败了
我只需要删除行(或文件),并且spy()
工作。确保不调用类中的方法的一种方法是使用伪方法重写该方法
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
@Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
另一种可能会导致spies出现问题的情况是,您正在测试SpringBeans(使用SpringTestFramework)或其他在测试期间代理对象的框架
范例
@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前往救援
如果我们使用@Autowired
注释来代替@SpyBean
注释,我们将解决上述问题,SpyBean注释也将注入存储库对象,但它将首先由Mockito代理,并且在调试器中看起来像这样
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
代码如下:
@SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
派对有点晚了,但上面的解决方案对我不起作用,所以分享我的0.02$
Mokcito版本:1.10.19
MyClass.java
private int handleAction(List<String> argList, String action)
以下方法对我不起作用(实际的方法是
doReturn(0).when(spy , "handleAction", any(), anyString());
doReturn(0).when(spy , "handleAction", null, null);
doReturn(0).when(spy , "handleAction", any(List.class), anyString());