[英]Mockito: how to stub void methods to run some code when called
I want to stub a repository class to test another class (Holder class) that has a repository.我想存根一个存储库类来测试另一个具有存储库的类(Holder 类)。 The repository interface supports CRUD operations, and has many methods, but my unit test on the Holder class only needs to call two of them.
存储库接口支持CRUD操作,方法很多,但是我对Holder类的单元测试只需要调用其中的两个。 The repository interface:
存储库界面:
public interface IRepo {
public void remove(String... sarr);
public void add(String... sarr);
//Lots of other methods I don't need now
}
I want to create a repository mock that can store instances, define logic for add
and remove
only, and also provide a means of checking what is stored on it after calling add and remove.我想创建一个可以存储实例的存储库模拟,定义仅用于
add
和remove
逻辑,并提供一种在调用添加和删除后检查存储在其中的内容的方法。
If I do:如果我做:
IRepo repoMock = mock(IRepo.class);
Then I have a dumb object that does nothing on each method.然后我有一个愚蠢的对象,它对每种方法都不做任何事情。 That's OK, now I just need to define behaviour for add and remove.
没关系,现在我只需要定义添加和删除的行为。
I could create a Set<String>
and stub only those two methods to work on the set.我可以创建一个
Set<String>
并仅存根这两种方法来处理该集合。 Then I'd instantiate a Holder that has an IRepo, inject the partially stubbed mock, and after exercising the holder, check the set to verify it contains what it should.然后,我会实例化一个具有 IRepo 的 Holder,注入部分存根的模拟,并在运行该持有者后,检查该集合以验证它包含应有的内容。
I've managed to partially stub a void method like remove
using the deprecated method stubVoid
:我已经设法使用已弃用的方法
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());
But is deprecated, and it is not much better than creating a partial implementation for IRepo.但已弃用,并不比为 IRepo 创建部分实现好多少。 Is there a better way?
有没有更好的办法?
NOTE: Java 7 answers only please, this should run in Android.注意:请只回答 Java 7,这应该在 Android 中运行。
You can use 您可以使用
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
//DO SOMETHING
return null;
}
}).when(...).remove(Matchers.<String>anyVararg());
From the Javadoc: 来自Javadoc:
Use doAnswer() when you want to stub a void method with generic Answer.
如果要使用通用答案存根void方法,请使用doAnswer()。
Stubbing voids requires different approach from Mockito.when(Object) because the compiler does not like void methods inside brackets...
Stubbing void需要Mockito.when(Object)的不同方法,因为编译器不喜欢括号内的void方法...
Example:
例:
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Mock mock = invocation.getMock();
return null;
}}).when(mock).someMethod();
See examples in javadoc for Mockito 请参阅javadoc for Mockito中的示例
Suppose you have 假设你有
public class IFace {
public void yourMethod() {
}
}
Then to mock it you need 然后嘲笑你需要的
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();
If you really don't like to return null
in your implementation of Answer
, you can create your own Answer implementation that delegates to a void method: 如果你真的不想在你的
Answer
实现中return null
,你可以创建自己的Answer实现,委托给一个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);
}
Then your test has one line less: 然后你的测试少了一行:
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());
Or, if you just need the arguments from the invocation: 或者,如果您只需要调用的参数:
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);
}
In addition to https://stackoverflow.com/a/32139397/4471199 you can use lambda:除了https://stackoverflow.com/a/32139397/4471199之外,您还可以使用 lambda:
Mockito.doAnswer(
answer -> {
// DO SOMETHING
return null;
}
).when(repoMock).remove(Matchers.<String>anyVararg());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.