Home » Java » How to make mock to void methods with mockito

How to make mock to void methods with mockito

Posted by: admin November 2, 2017 Leave a comment

Questions:

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 find an example on the Internet, but didn’t succeed.

My class looks like

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 are not triggered with mock. =(
I want to show above mentioned system state. And make assertion according to them.

Answers:

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.

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 doAnswer method to mock the 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());

Questions:
Answers:

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

Questions:
Answers:

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.

Questions:
Answers:

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 Spy this way:

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 spy object and not on the world object. For example:

assertEquals(0,spy.methodToTestThatShouldReturnZero());

Questions:
Answers:

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(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”:

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

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

Questions:
Answers:

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.

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

Questions:
Answers:

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("[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 mock and test void methods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)

Questions:
Answers:

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.

Questions:
Answers:

@ashley : works for me

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