如何用Mockito模拟空方法

如何模拟返回类型为空的方法?

我实现了一个观察者模式,但我不能用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();}

系统不是用mock触发的。

我想展示上述系统状态。并根据它们进行断言。

1087128 次浏览

看看Mockitoapi文档。正如链接文档所提到的(点doAnswer()2),您可以使用Mockito框架中的doThrow()doAnswer()doNothing()doReturn()系列方法中的任何一个来模拟false方法。

例如,

Mockito.doThrow(new Exception()).when(instance).methodName();

或者如果你想把它和后续行为结合起来,

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

假设您正在下面的类World中模拟settersetState(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());

所谓问题的解决方案是使用spyMockito.spy(…)而不是mockMockito.mock()

间谍使我们能够部分地嘲笑。莫奇托擅长这件事。因为你有一个不完整的类,用这种方式你嘲笑这个类中的一些必需的地方。

向一堆添加另一个答案(没有双关语)…

如果您不能\不想使用间谍,您确实需要调用do回答方法。但是,您不一定需要滚动自己的答案。有几个默认实现。值得注意的是,调用实名方法

在实践中,它看起来像这样:

doAnswer(new CallsRealMethods()).when(mock).voidMethod(any(SomeParamClass.class));

或:

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock).voidMethod(any(SomeParamClass.class));

我想我已经找到了一个更简单的答案,为一个方法调用real方法(即使它有一个空返回),你可以这样做:

Mockito.doCallRealMethod().when(<objectInstance>).<method>();<objectInstance>.<method>();

或者,您可以为该类的所有方法调用real方法,这样做:

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);

我认为你的问题是由于你的测试结构造成的。我发现很难将模拟与测试类中实现接口的传统方法混合在一起(就像你在这里所做的那样)。

如果您将侦听器实现为Mock,则可以验证交互。

Listener listener = mock(Listener.class);w.addListener(listener);world.doAction(..);verify(listener).doAction();

这应该让你确信“世界”正在做正确的事情。

补充一下@sateesh所说的,当你只是想模拟一个空方法以防止测试调用它时,你可以这样使用Spy

World world = new World();World spy = Mockito.spy(world);Mockito.doNothing().when(spy).methodToMock();

当您想运行测试时,请确保在test中对spy对象而不是world对象调用该方法。例如:

assertEquals(0, spy.methodToTestThatShouldReturnZero());

首先:您应该始终导入mockito静态,这样代码将更具可读性(和直观性):

import static org.mockito.Mockito.*;

对于部分嘲笑,仍然保留原始功能,其余mockito提供“间谍”。

您可以按如下方式使用它:

private World world = spy(new World());

要从执行中消除方法,您可以使用如下内容:

doNothing().when(someObject).someMethod(anyObject());

要为方法提供一些自定义行为,请使用“当”和“thenBack”:

doReturn("something").when(this.world).someMethod(anyObject());

有关更多示例,请在文档中找到优秀的mockito样品。

如何使用mockito模拟空方法-有两种选择:

  1. doAnswer-如果我们希望我们的mocked ull方法做一些事情(尽管无效,但模拟行为)。
  2. doThrow-如果您想从mocked val方法抛出异常,则有Mockito.doThrow()

以下是如何使用它的示例(不是理想的用例,只是想说明基本用法)。

@Testpublic void testUpdate() {
doAnswer(new Answer<Void>() {
@Overridepublic 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 testCustomer customer = service.changeEmail("old@test.com", "new@test.com");
//some assertsassertThat(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 testCustomer customer = service.changeEmail("old@test.com", "new@test.com");
}}

您可以在我的文章如何用Mockito模拟(带示例的综合指南)中找到有关如何使用Mockito模拟测试无效方法的更多详细信息

在Java8中,假设您有org.mockito.Mockito.doAnswer的静态导入,这可以变得更清晰:

doAnswer(i -> {// Do stuff with i.getArguments() herereturn null;}).when(*mock*).*method*(*methodArguments*);

return null;很重要,如果没有它,编译将失败并出现一些相当模糊的错误,因为它无法为doAnswer找到合适的覆盖。

例如,一个ExecutorService可以立即执行传递给execute()的任何Runnable,可以使用以下方式实现:

doAnswer(i -> {((Runnable) i.getArguments()[0]).run();return null;}).when(executor).execute(any());

在您的示例中,您应该模拟监听器项并使用Mockito.verify来检查与它的交互

如果你需要在mocked val方法中执行一些操作,并且你需要操作发送给val方法的参数;你可以将Mockito.do答案与ArgumentCaptor.capture方法结合起来。

假设您有SpaceService自动连接银河服务,它有一个名为服务类型的空方法。

您想为SpaceService中的一个方法编写测试,该方法调用银河服务的空方法。您的星球也是在SpaceService内部生成的。所以你没有任何机会嘲笑它。

这是您要为其编写测试的示例SpaceService类。

class SpaceService {@Autowiredprivate GalaxyService galaxyService;
public Date someCoolSpaceServiceMethod() {// does something
Planet planet = new World();galaxyService.someServiceMethod(planet); //Planet updated in this method.
return planet.getCurrentTime();}}

GalaxyService.some服务方法需要一个行星参数。在方法中做了一些事情。请参阅:

GalaxyService {public void someServiceMethod(Planet planet) {//do fancy stuff here. about solar system etc.
planet.setTime(someCalculatedTime); // the thing that we want to test.
// some more stuff.}}

你想测试这个特性。

下面是一个例子:

ArgumentCaptor<World> worldCaptor = ArgumentCaptor.forClass(World.class);Date testDate = new Date();
Mockito.doAnswer(mocked-> {World capturedWorld = worldCaptor.getValue();world.updateTime(testDate);return null;}).when(galaxyService.someServiceMethod(worldCaptor.capture());
Date result = spaceService.someCoolSpaceServiceMethod();
assertEquals(result, testDate);