Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito - separately verifying multiple invocations on the same method

Tags:

java

mockito

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?

like image 417
bcoughlan Avatar asked Feb 10 '16 16:02

bcoughlan


People also ask

How do you mock the same method with different parameters?

thenAnswer( invocation -> { Object argument = invocation. getArguments()[1]; if (argument. equals(new ARequest(1, "A"))) { return new AResponse(1, "passed"); } else if (argument. equals(new ARequest(2, "2A"))) { return new AResponse(2, "passed"); } else if (argument.

What is the difference between doReturn and thenReturn?

Following are the differences between thenReturn and doReturn : * Type safety : doReturn takes Object parameter, unlike thenReturn . Hence there is no type check in doReturn at compile time. In the case of thenReturn , whenever the type mismatches during runtime, the WrongTypeOfReturnValue exception is raised.

What is EQ Mockito?

Mockito Argument Matcher - eq() When we use argument matchers, then all the arguments should use matchers. If we want to use a specific value for an argument, then we can use eq() method. when(mockFoo. bool(eq("false"), anyInt(), any(Object. class))).


3 Answers

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()); 
like image 103
Tunaki Avatar answered Sep 28 '22 14:09

Tunaki


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)); 
like image 26
Todd Avatar answered Sep 28 '22 13:09

Todd


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());
    }
}
like image 22
bcoughlan Avatar answered Sep 28 '22 14:09

bcoughlan