How to mock void methods with Mockito

前端 未结 9 2095
情话喂你
情话喂你 2020-11-22 12:21

How to mock methods with void return type?

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

And I tried to fin

相关标签:
9条回答
  • 2020-11-22 12:58

    In Java 8 this can be made a little cleaner, assuming you have a static import for 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.

    For example an ExecutorService that just immediately executes any Runnable passed to execute() could be implemented using:

    doAnswer(i -> {
      ((Runnable) i.getArguments()[0]).run();
      return null;
    }).when(executor).execute(any());
    
    0 讨论(0)
  • 2020-11-22 12:59

    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:

    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);
    
    0 讨论(0)
  • 2020-11-22 12:59

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

    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.

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

    You could find more details on how to mock and test void methods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)

    0 讨论(0)
  • 2020-11-22 13:05

    The solution of so-called problem is to use a spy Mockito.spy(...) instead of a mock Mockito.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.

    0 讨论(0)
  • 2020-11-22 13:08

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

    import static org.mockito.Mockito.*;
    

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

    You can use it as follows:

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

    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":

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

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

    0 讨论(0)
  • 2020-11-22 13:08

    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.

    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.

    0 讨论(0)
提交回复
热议问题