如何使用Mockito模拟void方法

时间:2010-02-16 20:54:40

标签: java unit-testing mocking mockito

如何使用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();
}

系统不会被模拟触发。 =( 我想显示上面提到的系统状态。并根据他们做出断言。

13 个答案:

答案 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方法 - 有两个选项:

  1. doAnswer - 如果我们希望我们的模拟void方法做某事(尽管是无效的模仿行为)。
  2. doThrow - 如果你想从模拟的void方法中抛出异常,那么Mockito.doThrow()
  3. 以下是如何使用它的示例(不是理想的用例,只是想说明基本用法)。

    @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)

可以根据情况采用以下两种方式完成操作:

  1. doAnswer-如果我们希望模拟的void方法做某事(尽管无效,也要模拟行为)。

  2. 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来检查与之交互