如何使用void返回类型模拟方法?
我实现了一个观察者模式,但我不能用Mockito模仿它,因为我不知道如何。
我试图在互联网上找到一个例子,但没有成功。
我的班级看起来像这样:
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();
}
系统不会被模拟触发。 =( 我想显示上面提到的系统状态。并根据他们做出断言。
答案 0 :(得分:1023)
看看Mockito API docs。正如链接文档所提到的(第12点),您可以使用Mockito框架中的任何doThrow()
,doAnswer()
,doNothing()
,doReturn()
方法系列来模拟void方法。
例如,
Mockito.doThrow(new Exception()).when(instance).methodName();
或者如果您想将其与后续行为相结合,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
假设您正在考虑在下面的类World中模拟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());
答案 1 :(得分:93)
我想我已经找到了一个更简单的答案,只为一个方法调用真正的方法(即使它有一个void返回)你可以这样做:
Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();
或者,您可以为该类的所有方法调用实际方法,执行此操作:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
答案 2 :(得分:61)
添加@sateesh所说的,当你只想模拟一个void方法以防止测试调用它时,你可以用这种方式Spy
:
World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();
如果要运行测试,请确保在spy
对象上调用测试方法而不是world
对象。例如:
assertEquals(0,spy.methodToTestThatShouldReturnZero());
答案 3 :(得分:51)
所谓问题的解决方案是使用spy
Mockito.spy(...)而不是mock
Mockito.mock(..)。
间谍使我们能够进行局部嘲笑。 Mockito擅长此事。因为你有一个不完整的类,所以你可以通过这种方式在这个类中模拟一些必需的地方。
答案 4 :(得分:23)
首先:你应该总是导入mockito静态,这样代码将更具可读性(和直观性):
import static org.mockito.Mockito.*;
对于部分嘲讽并且仍然保留其余模拟优惠的原始功能&#34; Spy&#34;。
您可以按如下方式使用它:
private World world = spy(World.class);
要消除执行方法,您可以使用以下内容:
doNothing().when(someObject).someMethod(anyObject());
给方法一些自定义行为使用&#34;当&#34;用&#34;然后返回&#34;:
doReturn("something").when(this.world).someMethod(anyObject());
有关更多示例,请在文档中找到mockito示例。
答案 5 :(得分:19)
如何使用mockito模拟void方法 - 有两个选项:
doAnswer
- 如果我们希望我们的模拟void方法做某事(尽管是无效的模仿行为)。doThrow
- 如果你想从模拟的void方法中抛出异常,那么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");
}
}
您可以在我的帖子How to mock with Mockito (A comprehensive guide with examples)
模拟和测试 无效方法的更多详细信息>答案 6 :(得分:14)
为这一堆添加另一个答案(没有双关语)...
如果你不能\不想使用间谍,你需要调用doAnswer方法。但是,您不一定需要推出自己的Answer。有几个默认实现。值得注意的是,CallsRealMethods。
在实践中,它看起来像这样:
doAnswer(new CallsRealMethods()).when(mock)
.voidMethod(any(SomeParamClass.class));
或者:
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
.voidMethod(any(SomeParamClass.class));
答案 7 :(得分:8)
在Java 8中,假设您有org.mockito.Mockito.doAnswer
的静态导入,这可以更清晰一点:
doAnswer(i -> {
// Do stuff with i.getArguments() here
return null;
}).when(*mock*).*method*(*methodArguments*);
return null;
很重要,如果没有它,编译将失败并出现一些相当模糊的错误,因为它无法为doAnswer
找到合适的覆盖。
例如,只需立即执行传递给ExecutorService
的任何Runnable
的{{1}}即可使用以下内容实现:
execute()
答案 8 :(得分:5)
我认为您的问题是由于您的测试结构造成的。我发现很难将模拟与在测试类中实现接口的传统方法混合在一起(正如你在这里所做的那样)。
如果您将侦听器实现为Mock,则可以验证交互。
Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();
这应该让你满意的是“世界”。正在做正确的事。
答案 9 :(得分:0)
@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); } }
答案 10 :(得分:0)
可以根据情况采用以下两种方式完成操作:
doAnswer-如果我们希望模拟的void方法做某事(尽管无效,也要模拟行为)。
doThrow-如果您想从模拟的void方法中引发异常,我们也有Mockito.doThrow()。
答案 11 :(得分:0)
使用Mockito.doThrow,如下所示:
Mockito.doThrow(new Exception()).when(instance).methodName();
您可以尝试以下示例:
public void testCloseStreamOnException() throws Exception {
OutputStream outputStream = Mockito.mock(OutputStream.class);
IFileOutputStream ifos = new IFileOutputStream(outputStream);
Mockito.doThrow(new IOException("Dummy Exception")).when(outputStream).flush();
try {
ifos.close();
fail("IOException is not thrown");
} catch (IOException ioe) {
assertEquals("Dummy Exception", ioe.getMessage());
}
Mockito.verify(outputStream).close();
}
来源:http://apisonar.com/java-examples/org.mockito.Mockito.doThrow.html#Example-19
答案 12 :(得分:0)
在您的示例中,您应该模拟Listener项目并使用Mockito.verify来检查与之交互