How to make mock to void methods with mockito
如何模拟void返回类型的方法?
我实现了一个观测者模式,但是我不能用mockito来模拟它,因为我不知道怎么做。
我试图在网上找到一个例子,但没有成功。
我的课看起来像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class World { List<Listener> listeners; void addListener(Listener item) { listeners.add(item); } void doAction(Action goal,Object obj) { setState("i received"); goal.doAction(obj); setState("i finished"); } private string state; //setter getter state } public class WorldTest implements Listener { @Test public void word{ World w= mock(World.class); w.addListener(this); ... ... } } interface Listener { void doAction(); } |
系统不是用模拟触发的。=(我想显示上面提到的系统状态。并根据他们做出断言。
看看Mockito API文档。正如链接文档所提到的(第12点),您可以使用从mockito框架到mock void方法的任何
例如,
1 |
或者如果你想把它和后续行为结合起来,
1 |
假设您正在下面的类世界中模拟setter
1 2 3 4 5 6 7 8 |
我想我找到了一个更简单的问题答案,只需为一个方法调用real方法(即使它有一个空返回),就可以这样做:
1 2 | Mockito.doCallRealMethod().when(<objectInstance>).<method>(); <objectInstance>.<method>(); |
或者,可以为该类的所有方法调用real方法,这样做:
1 | <Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS); |
除了@satesh所说的,当您只想模拟一个void方法以防止测试调用它时,您可以使用
1 2 3 | World world = new World(); World spy = Mockito.spy(world); Mockito.doNothing().when(spy).methodToMock(); |
当您想要运行测试时,请确保您在测试中调用了
1 | assertEquals(0,spy.methodToTestThatShouldReturnZero()); |
所谓问题的解决方法是使用
间谍使我们能够部分嘲笑。莫基托擅长这件事。因为你的课不完整,所以你在这节课上嘲弄了一些必修的地方。
首先:您应该始终导入mockito static,这样代码的可读性(和直观性)会更高:
1 | import static org.mockito.Mockito.*; |
对于部分模拟和仍然保持原有功能的其余Mockito提供"间谍"。
您可以按如下方式使用:
1 | private World world = spy(World.class); |
要消除正在执行的方法,可以使用如下方法:
1 | doNothing().when(someObject).someMethod(anyObject()); |
要为方法提供一些自定义行为,请使用"when"和"thenreturn":
1 | doReturn("something").when(this.world).someMethod(anyObject()); |
更多示例请在文档中找到mockito示例。
如何用mockito模拟void方法-有两个选项:
下面是一个如何使用它的示例(不是一个理想的用例,只是想说明基本用法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | @Test public void testUpdate() { doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] arguments = invocation.getArguments(); if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) { Customer customer = (Customer) arguments[0]; String email = (String) arguments[1]; customer.setEmail(email); } return null; } }).when(daoMock).updateEmail(any(Customer.class), any(String.class)); // calling the method under test Customer customer = service.changeEmail("[email protected]","[email protected]"); //some asserts assertThat(customer, is(notNullValue())); assertThat(customer.getEmail(), is(equalTo("[email protected]"))); } @Test(expected = RuntimeException.class) public void testUpdate_throwsException() { doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class)); // calling the method under test Customer customer = service.changeEmail("[email protected]","[email protected]"); } } |
你可以在我的文章中找到更多关于如何用mockito模拟和测试void方法的细节,如何用mockito模拟(一个综合性的例子指南)
给这群人添加另一个答案(没有双关语的意思)。
如果您不想使用Spy,则需要调用DoAnswer方法。但是,您不必滚动自己的答案。有几个默认实现。值得注意的是,callsrealmethods。
实际上,它看起来是这样的:
1 2 | doAnswer(new CallsRealMethods()).when(mock) .voidMethod(any(SomeParamClass.class)); |
或:
1 2 | doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock) .voidMethod(any(SomeParamClass.class)); |
在Java 8中,如果对EDOCX1具有15的静态输入,则可以使其更干净一些:
1 2 3 4 | doAnswer(i -> { // Do stuff with i.getArguments() here return null; }).when(*mock*).*method*(*methodArguments*); |
例如,刚刚执行任何传递给
1 2 3 4 | doAnswer(i -> { ((Runnable) i.getArguments()[0]).run(); return null; }).when(executor).execute(any()); |
我认为你的问题是由于你的测试结构。我发现很难将模拟与在测试类中实现接口的传统方法混合在一起(正如您在这里所做的)。
如果您将侦听器实现为一个模拟,那么您可以验证交互。
1 2 3 4 | Listener listener = mock(Listener.class); w.addListener(listener); world.doAction(..); verify(listener).doAction(); |
这应该能让你确信"世界"正在做正确的事情。
@ashley : works for me
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 public class AssetChangeListenerImpl extends
AbstractAssetChangeListener implements AssetChangeListener {
@Override
public void onChangeEvent(final EventMessage message) throws EventHubClientException {
execute(message);
}
}
}
public class AbstractAssetChangeListener {
protected void execute( final EventMessage message ) throws EventHubClientException {
executor.execute( new PublishTask(getClient(), message) );
} } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest {
public void testExecute() throws EventHubClientException {
EventMessage message = createEventMesage(EventType.CREATE);
assetChangeListener.execute(message);
verify(assetChangeListener, times(1)).execute(message);
} }