bcoughlan
bcoughlan

Reputation: 26627

Mockito - separately verifying multiple invocations on the same method

import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;

import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;


public class MockitoTest {


    public static class TestMock {
        public void doIt(String s) {
        }
    }

    public static void main(String[] args) {
        TestMock mock = Mockito.mock(TestMock.class);
        mock.doIt("1");
        mock.doIt("2");

        ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
        verify(mock, atLeastOnce()).doIt(argument.capture());
        System.out.println(argument.getValue());
        verify(mock, atLeastOnce()).doIt(argument.capture());
        System.out.println(argument.getValue());
    }
}

I expected this to print 1 2 but it instead prints 2 2. It seems the '1' invocation is lost. Is there a way that I can verify that verifications happened with 1 and then 2?

Upvotes: 37

Views: 35563

Answers (3)

Tunaki
Tunaki

Reputation: 137289

You can call ArgumentCaptor.getAllValues() instead of getValue(). This will return all captured values:

Returns all captured values. Use it when capturing varargs or when the verified method was called multiple times.

In this case, it will return a List<String> containing 1 and 2.

The getValue() method only returns the last captured value:

Returns the captured value of the argument.

If the method was called multiple times then it returns the latest captured value

In your code, you can replace atLeastOnce() with the more precise times(2) since the mock was called 2 times. You don't need to have two distinct calls to verify to capture the arguments: Mockito will be able to capture all arguments passed to the mock with just one call.

TestMock mock = Mockito.mock(TestMock.class);
mock.doIt("1");
mock.doIt("2");

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock, times(2)).doIt(argument.capture()); // verify that it was call 2 times and capture the values given

System.out.println(argument.getAllValues());

Upvotes: 51

bcoughlan
bcoughlan

Reputation: 26627

What I actually needed in the end was in-order verification for incremental verification, using the calls() VerificationMode

public static class A {

    public void a(int x) {}

    public void b() {}

}

public static void main(String[] args) {
    A a = mock(A.class);
    a.b();
    a.a(1);
    a.a(1);
    a.a(2);
    a.a(3);
    a.a(4);

    InOrder inOrder = Mockito.inOrder(a);
    // Verifies [1,1]
    inOrder.verify(a, calls(2)).a(1);
    {
        // Verifies [2]
        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
        inOrder.verify(a, calls(1)).a(argument.capture());
        System.out.println(argument.getAllValues());
    }
    {
        // Verifies [3,4]
        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
        inOrder.verify(a, calls(2)).a(argument.capture());
        System.out.println(argument.getAllValues());
    }
}

Upvotes: 6

Todd
Todd

Reputation: 31720

Switch to getAllValues() from getValues(). It will return a list of all the captures it performs on your mock.

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock, atLeastOnce()).doIt(argument.capture());
System.out.println(argument.getAllValues().get(0));
verify(mock, atLeastOnce()).doIt(argument.capture());
System.out.println(argument.getAllValues().get(1));

Upvotes: 7

Related Questions