Java Mockito:如何在调用时存根void方法以运行某些代码
我想存根一个存储库类来测试另一个拥有存储库的类(Holder类)。repository接口支持CRUD操作,并且有许多方法,但是我对Holder类的单元测试只需要调用其中的两个。存储库界面:Java Mockito:如何在调用时存根void方法以运行某些代码,java,unit-testing,mockito,void,stubbing,Java,Unit Testing,Mockito,Void,Stubbing,我想存根一个存储库类来测试另一个拥有存储库的类(Holder类)。repository接口支持CRUD操作,并且有许多方法,但是我对Holder类的单元测试只需要调用其中的两个。存储库界面: public interface IRepo { public void remove(String... sarr); public void add(String... sarr); //Lots of other methods I don't need now } 我想
public interface IRepo {
public void remove(String... sarr);
public void add(String... sarr);
//Lots of other methods I don't need now
}
我想创建一个存储库模拟,它可以存储实例,只为add
和remove
定义逻辑,还可以提供一种在调用add和remove之后检查存储在其中的内容的方法。
如果我这样做:
IRepo repoMock = mock(IRepo.class);
然后我有一个哑对象,它对每个方法都不做任何操作。没关系,现在我只需要定义add和remove的行为
我可以创建一个集合
并只存根这两个方法来处理集合。然后,我将实例化一个具有IRepo的Holder,注入部分存根的mock,在执行Holder之后,检查集合以验证它包含应该包含的内容
我已使用不推荐使用的方法stubVoid
,成功地部分存根了一个void方法,如remove
:
Set<String> mySet = new HashSet<>();
stubVoid(repoMock).toAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
return null;
}
}).on().remove(Matchers.<String>anyVararg());
Set mySet=new HashSet();
stubVoid(repoMock).toAnswer(新答案){
@凌驾
公共Void应答(invocationmock调用)抛出可丢弃的{
对象[]args=invocation.getArguments();
字符串[]stringsToDelete=(字符串[])参数[0];
removeAll(Arrays.asList(stringsToDelete));
返回null;
}
}).on().remove(Matchers.anyVararg());
但是它已经被弃用了,它并不比为IRepo创建一个部分实现好多少。有更好的办法吗
注意:请只回答Java 7,这应该在Android中运行。假设您有
public class IFace {
public void yourMethod() {
}
}
然后你需要模仿它
IFace mock = Mockito.mock(IFace.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
//PUT YOUR CODE HERE
return null;
}
}).when(mock).yourMethod();
你可以用
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
//DO SOMETHING
return null;
}
}).when(...).remove(Matchers.<String>anyVararg());
请参阅javadoc for Mockito中的示例如果在
应答
的实现中确实不喜欢返回null
,则可以创建自己的应答实现,该实现委托给void方法:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation);
return null;
}
protected abstract void doSomething(InvocationOnMock invocation);
}
公共抽象类DoesMethingAnswer实现了答案{
@凌驾
公共Void应答(invocationmock调用)抛出可丢弃的{
doSomething(调用);
返回null;
}
受保护的抽象void doSomething(invocationmock调用);
}
那么您的测试少了一行:
Set<String> mySet = new HashSet<>();
Mockito.doAnswer(new DoesSomethingAnswer() {
@Override
protected void doSomething(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
String[] stringsToDelete = (String[]) args[0];
mySet.removeAll(Arrays.asList(stringsToDelete));
}
}).when(repoMock).remove(Matchers.<String> anyVararg());
Set mySet=new HashSet();
Mockito.doAnswer(新的DoesSomethingAnswer(){
@凌驾
受保护的void doSomething(invocationMock调用){
对象[]args=invocation.getArguments();
字符串[]stringsToDelete=(字符串[])参数[0];
removeAll(Arrays.asList(stringsToDelete));
}
}).when(repoMock).remove(Matchers.anyVararg());
或者,如果您只需要调用中的参数:
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation.getArguments());
return null;
}
protected abstract void doSomething(Object[] args);
}
公共抽象类DoesMethingAnswer实现了答案{
@凌驾
公共Void应答(invocationmock调用)抛出可丢弃的{
doSomething(invocation.getArguments());
返回null;
}
受保护的抽象无效剂量测量(对象[]args);
}
有趣的是,没有doSomething
接受一个可运行的答案,而不必破解一个无效的答案。我的用例是不是太牵强了,不值得放在Mockito的API中?我怀疑是否有任何库可以满足所有用户的需求。Mockito很容易扩展(见我的答案),几乎可以用于任何目的。顺便说一下,Runnable在您的示例中不起作用,因为您需要调用参数。修复了我在测试中途试图强制更改某些数据的问题,谢谢!
public abstract class DoesSomethingAnswer implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
doSomething(invocation.getArguments());
return null;
}
protected abstract void doSomething(Object[] args);
}