java Mockito:如何在调用时存根 void 方法以运行一些代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32139252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mockito: how to stub void methods to run some code when called
提问by Mister Smith
I want to stub a repository class to test another class (Holder class) that has a repository. 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. The repository interface:
我想存根一个存储库类来测试另一个具有存储库的类(Holder 类)。存储库接口支持CRUD操作,方法很多,但是我对Holder类的单元测试只需要调用其中的两个。存储库界面:
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
仅提供一种在调用 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. 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.
我可以创建一个Set<String>
并仅存根这两种方法来在集合上工作。然后,我会实例化一个具有 IRepo 的 Holder,注入部分存根的模拟,并在运行该持有者后,检查该集合以验证它包含应有的内容。
I've managed to partially stub a void method like remove
using the deprecated method stubVoid
:
我已经成功地部分存根了一个 void 方法,比如remove
使用不推荐使用的方法stubVoid
:
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. Is there a better way?
但已弃用,并不比为 IRepo 创建部分实现好多少。有没有更好的办法?
NOTE: Java 7 answers only please, this should run in Android.
注意:请只回答 Java 7,这应该在 Android 中运行。
回答by Jens
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.
Stubbing voids requires different approach from Mockito.when(Object) because the compiler does not like void methods inside brackets...
Example:
当您想使用通用答案存根无效方法时,请使用 doAnswer()。
Stubbing voids 需要与 Mockito.when(Object) 不同的方法,因为编译器不喜欢括号内的 void 方法......
例子:
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
请参阅 Mockito 的 javadoc 中的示例
回答by talex
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();
回答by Ruben
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:
如果你真的不喜欢return null
你的 实现Answer
,你可以创建你自己的 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);
}