如何使模拟无效方法与mockito
如何用void返回types来模拟方法?
我实现了观察者模式,但是我不能用Mockito来嘲笑它,因为我不知道如何。
我试图在互联网上find一个例子,但没有成功。
我的class长看起来像
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),您可以使用doThrow()
任何doThrow()
, doAnswer()
, doNothing()
, doReturn()
系列方法来模拟void方法。
例如,
Mockito.doThrow(new Exception()).when(instance).methodName();
或者如果您想要将其与后续行为相结合,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
假设你正在嘲笑Setter setState(String s)
类中的setter setState(String s)
,下面是代码使用doAnswer
方法来模拟setState
。
World mockWorld = mock(World.class); doAnswer(new Answer<Void>() { public Void answer(InvocationOnMock invocation) { Object[] args = invocation.getArguments(); System.out.println("called with arguments: " + Arrays.toString(args)); return null; } }).when(mockWorld).setState(anyString());
我想我已经find了一个简单的答案来解决这个问题,只需要一个方法来调用真正的方法(即使它有一个void return),你可以这样做:
Mockito.doCallRealMethod().when(<objectInstance>).<method>(); <objectInstance>.<method>();
或者,你可以为这个类的所有方法调用真正的方法,这样做:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
所谓问题的解决scheme是使用spy
Mockito.spy(…)而不是mock
Mockito.mock(..) 。
间谍让我们部分嘲笑。 Mockito擅长这件事。 因为你有不完整的课,所以你在这个课上嘲笑了一些必要的地方。
加上@sateesh说的,当你只是想嘲笑一个无效的方法,以防止testing调用它,你可以这样使用一个Spy
:
World world = new World(); World spy = Mockito.spy(world); Mockito.doNothing().when(spy).methodToMock();
当你想运行你的testing时,确保你调用了spy
对象的testing方法,而不是world
对象。 例如:
assertEquals(0,spy.methodToTestThatShouldReturnZero());
首先:你应该总是导入mockito静态,这样代码将更可读(和直观):
import static org.mockito.Mockito.*;
对于部分嘲讽,仍然保持其他原始functionmockito提供“间谍”。
你可以使用它如下:
private World world = spy(World.class);
要消除执行的方法,你可以使用这样的东西:
doNothing().when(someObject).someMethod(anyObject());
给一个方法使用“then”时使用“thenReturn”一些自定义行为:
doReturn("something").when(this.world).someMethod(anyObject());
有关更多示例,请在文档中findmockito示例。
如何用mockito来模拟void方法 – 有两种select:
-
doAnswer
– 如果我们想要我们的虚拟无效方法做一些事情(嘲笑行为,尽pipe是无效的)。 -
doThrow
– 如果你想从Mockito.doThrow()
的void方法抛出一个exception,那么就有Mockito.doThrow()
。
以下是如何使用它的一个例子(不是一个理想的用例,而是想说明基本用法)。
@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("old@test.com", "new@test.com"); //some asserts assertThat(customer, is(notNullValue())); assertThat(customer.getEmail(), is(equalTo("new@test.com"))); } @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("old@test.com", "new@test.com"); } }
你可以find更多的细节,如何在我的文章中用Mockito来模拟和testing void方法如何用Mockito模拟(一个带有例子的综合指南)
增加另一个答案的一堆(没有双关语意图)…
如果你不能\不想使用间谍,你需要调用doAnswer方法。 但是,您不一定需要推出自己的答案 。 有几个默认的实现。 值得注意的是, CallsRealMethods 。
在实践中,它看起来像这样:
doAnswer(new CallsRealMethods()).when(mock) .voidMethod(any(SomeParamClass.class));
要么:
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock) .voidMethod(any(SomeParamClass.class));
我认为你的问题是由于你的testing结构。 我发现很难将混淆与在testing类中实现接口的传统方法混淆(正如您在这里所做的那样)。
如果您将侦听器实现为模拟,则可以validation交互。
Listener listener = mock(Listener.class); w.addListener(listener); world.doAction(..); verify(listener).doAction();
这应该让你满意,“世界”是做正确的事情。
@ashley:为我工作
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); } }