Java 如何使用 Mockito 模拟 void 方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2276271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 05:35:52  来源:igfitidea点击:

How to mock void methods with Mockito

javaunit-testingmockingmockitovoid

提问by ibrahimyilmaz

How to mock methods with void return type?

如何使用 void 返回类型模拟方法?

I implemented an observer pattern but I can't mock it with Mockito because I don't know how.

我实现了一个观察者模式,但我不能用 Mockito 模拟它,因为我不知道如何。

And I tried to find an example on the Internet but didn't succeed.

我试图在互联网上找到一个例子但没有成功。

My class looks like this:

我的课是这样的:

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();
}

The system is not triggered with mock.

系统不是用模拟触发的。

I want to show the above-mentioned system state. And make assertions according to them.

我想显示上述系统状态。并根据它们做出断言。

采纳答案by sateesh

Take a look at the Mockito API docs. As the linked document mentions (Point # 12) you can use any of the doThrow(),doAnswer(),doNothing(),doReturn()family of methods from Mockito framework to mock void methods.

查看 Mockito API 文档。正如链接文档中提到的(第 12 点),您可以使用Mockito 框架中的任何doThrow(), doAnswer(), doNothing(),doReturn()系列方法来模拟 void 方法。

For example,

例如,

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

or if you want to combine it with follow-up behavior,

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

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

Presuming that you are looking at mocking the setter setState(String s)in the class World below is the code uses doAnswermethod to mock the setState.

假设您正在考虑在setState(String s)下面的类 World 中doAnswer模拟setter是代码使用方法来模拟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());

回答by ibrahimyilmaz

The solution of so-called problem is to use a spyMockito.spy(...)instead of a mockMockito.mock(..).

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

Spy enables us to partial mocking. Mockito is good at this matter. Because you have class which is not complete, in this way you mock some required place in this class.

Spy 使我们能够进行部分模拟。Mockito 擅长这件事。因为您的课程不完整,因此您可以通过这种方式模拟该课程中的某些必需位置。

回答by javamonkey79

Adding another answer to the bunch (no pun intended)...

添加另一个答案到一堆(没有双关语意)...

You do need to call the doAnswer method if you can't\don't want to use spy's. However, you don't necessarily need to roll your own Answer. There are several default implementations. Notably, CallsRealMethods.

如果您不能\不想使用间谍,则确实需要调用 doAnswer 方法。但是,您不一定需要推出自己的Answer。有几个默认实现。值得注意的是,CallsRealMethods

In practice, it looks something like this:

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

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

Or:

或者:

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

回答by MarcioB

I think I've found a simpler answer to that question, to call the real method for just one method (even if it has a void return) you can do this:

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

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

Or, you could call the real method for all methods of that class, doing this:

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

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

回答by ashley

I think your problems are due to your test structure. I've found it difficult to mix mocking with the traditional method of implementing interfaces in the test class (as you've done here).

我认为您的问题是由于您的测试结构造成的。我发现很难将模拟与在测试类中实现接口的传统方法混合使用(正如您在此处所做的那样)。

If you implement the listener as a Mock you can then verify the interaction.

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

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

This should satisfy you that the 'World' is doing the right thing.

这应该让您满意,“世界”正在做正确的事情。

回答by Omri374

Adding to what @sateesh said, when you just want to mock a void method in order to prevent the test from calling it, you could use a Spythis way:

添加@sateesh 所说的,当您只想模拟 void 方法以防止测试调用它时,您可以使用Spy这种方式:

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

When you want to run your test, make sure you call the method in test on the spyobject and not on the worldobject. For example:

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

assertEquals(0,spy.methodToTestThatShouldReturnZero());

回答by fl0w

First of all: you should always import mockito static, this way the code will be much more readable (and intuitive):

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

import static org.mockito.Mockito.*;

For partial mocking and still keeping original functionality on the rest mockito offers "Spy".

对于部分模拟并仍然保留其余部分的原始功能,mockito 提供“间谍”。

You can use it as follows:

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

private World world = spy(World.class);

To eliminate a method from being executed you could use something like this:

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

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

to give some custom behaviour to a method use "when" with an "thenReturn":

为方法使用“when”和“thenReturn”提供一些自定义行为:

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

For more examples please find the excellent mockito samples in the doc.

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

回答by Dilini Rajapaksha

How to mock void methods with mockito - there are two options:

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

  1. doAnswer- If we want our mocked void method to do something (mock the behavior despite being void).
  2. doThrow- Then there is Mockito.doThrow()if you want to throw an exception from the mocked void method.
  1. doAnswer- 如果我们想让我们的模拟 void 方法做一些事情(尽管是无效的,但还是模拟了行为)。
  2. doThrow- 然后,Mockito.doThrow()如果您想从模拟的 void 方法中抛出异常。

Following is an example of how to use it (not an ideal usecase but just wanted to illustrate the basic usage).

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

@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]");

}
}

You could find more details on how to mockand testvoidmethods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)

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

回答by Tim B

In Java 8 this can be made a little cleaner, assuming you have a static import for org.mockito.Mockito.doAnswer:

在 Java 8 中,这可以更简洁一些,假设您有一个静态导入org.mockito.Mockito.doAnswer

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

The return null;is important and without it the compile will fail with some fairly obscure errors as it won't be able to find a suitable override for doAnswer.

return null;是很重要的,没有它编译将一些比较隐蔽的错误失败,因为它无法找到一个合适的替代doAnswer

For example an ExecutorServicethat just immediately executes any Runnablepassed to execute()could be implemented using:

例如ExecutorService,可以使用以下方法实现立即执行Runnable传递给的任何内容execute()

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

回答by APISonar

Using Mockito.doThrow as in:

使用 Mockito.doThrow 如下:

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

you can try this nice example:

你可以试试这个很好的例子:

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();
  }

Source: http://apisonar.com/java-examples/org.mockito.Mockito.doThrow.html#Example-19

来源:http: //apisonar.com/java-examples/org.mockito.Mockito.doThrow.html#Example-19