580

I have a method that gets called twice, and I want to capture the argument of the second method call.

Here's what I've tried:

ArgumentCaptor<Foo> firstFooCaptor = ArgumentCaptor.forClass(Foo.class);
ArgumentCaptor<Foo> secondFooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar).doSomething(firstFooCaptor.capture());
verify(mockBar).doSomething(secondFooCaptor.capture());
// then do some assertions on secondFooCaptor.getValue()

But I get a TooManyActualInvocations Exception, as Mockito thinks that doSomething should only be called once.

How can I verify the argument of the second call of doSomething?

Eric Wilson
  • 57,719
  • 77
  • 200
  • 270

6 Answers6

1012

I think it should be

verify(mockBar, times(2)).doSomething(...)

Sample from mockito javadoc:

ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
verify(mock, times(2)).doSomething(peopleCaptor.capture());

List<Person> capturedPeople = peopleCaptor.getAllValues();
assertEquals("John", capturedPeople.get(0).getName());
assertEquals("Jane", capturedPeople.get(1).getName());
Community
  • 1
  • 1
proactif
  • 11,331
  • 1
  • 17
  • 11
  • 5
    Can you capture the arguments passed to `doSomething()` in each separate invocation with this? – matt b May 12 '11 at 17:19
  • 62
    It should be noted that in case you do something like this: `Person person = new Person("John"); doSomething(person); person.setName("Jane"); doSomething(person);` the captured argument will be the same twice (because actually it is the same person object), so `capturedPeople.get(0).getName() == capturedPeople.get(1).getName() == "Jane"` , see also https://groups.google.com/forum/#!msg/mockito/KBRocVedYT0/5HtARMl9r2wJ. – asmaier Dec 04 '14 at 14:46
  • 4
    This is nice, but how can I test two differently typed object invocations? For example ExecutorService.submit(new MyRunableImpl()); and then ExecutorService.submit(new MyAnotherRunableImpl()) ? – Leon Dec 14 '15 at 14:16
  • If one needs to handle the case described by @asmaier, I posted an answer here: http://stackoverflow.com/a/36574817/1466267 – SpaceTrucker Aug 05 '16 at 11:43
  • Hi @Leon, did u get the solution for the different type arguments? – Dinesh Kumar Oct 09 '17 at 10:03
  • 1
    For anyone still wondering about the answer to Leon's question, you'd use the common base class (`Runnable`) and, if needed, do a more specific type check on the captured argument. – Matthew Read Oct 24 '18 at 16:25
76

Since Mockito 2.0 there's also possibility to use static method Matchers.argThat(ArgumentMatcher). With the help of Java 8 it is now much cleaner and more readable to write:

verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("OneSurname")));
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("AnotherSurname")));

If you're tied to lower Java version there's also not-that-bad:

verify(mockBar).doSth(argThat(new ArgumentMatcher<Employee>() {
        @Override
        public boolean matches(Object emp) {
            return ((Employee) emp).getSurname().equals("SomeSurname");
        }
    }));

Of course none of those can verify order of calls - for which you should use InOrder :

InOrder inOrder = inOrder(mockBar);

inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("FirstSurname")));
inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("SecondSurname")));

Please take a look at mockito-java8 project which makes possible to make calls such as:

verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));
Maciej Dobrowolski
  • 11,561
  • 5
  • 45
  • 67
  • 3
    This is a nice technique. I'm currently getting some rather cryptic output though: "Wanted but not invoked: /n mockAppender.append( );" - the arg there is a `CharSequence`. Do you know of any way to get the report to print out the "wanted" arg properly? – mike rodent Feb 26 '17 at 16:39
  • 1
    @mikerodent The cryptic output can be fixed if you go the more verbose route of creating a class that implements ArgumentMatcher. Overriding the toString method in your implementation will provide any message you want in the mockito test output. – Noah Solomon Sep 26 '19 at 19:25
32

If you don't want to validate all the calls to doSomething(), only the last one, you can just use ArgumentCaptor.getValue(). According to the Mockito javadoc:

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

So this would work (assumes Foo has a method getName()):

ArgumentCaptor<Foo> fooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar, times(2)).doSomething(fooCaptor.capture());
//getValue() contains value set in second call to doSomething()
assertEquals("2nd one", fooCaptor.getValue().getName());
pd40
  • 3,187
  • 3
  • 20
  • 29
lreeder
  • 12,047
  • 2
  • 56
  • 65
26

You can also use @Captor annotated ArgumentCaptor. For example:

@Mock
List<String> mockedList;

@Captor
ArgumentCaptor<String> argCaptor;

@BeforeTest
public void init() {
    //Initialize objects annotated with @Mock, @Captor and @Spy.
    MockitoAnnotations.initMocks(this);
}

@Test
public void shouldCallAddMethodTwice() {
    mockedList.add("one");
    mockedList.add("two");
    Mockito.verify(mockedList, times(2)).add(argCaptor.capture());

    assertEquals("one", argCaptor.getAllValues().get(0));
    assertEquals("two", argCaptor.getAllValues().get(1));
}
Michał Stochmal
  • 5,895
  • 4
  • 36
  • 44
8

With Java 8's lambdas, a convenient way is to use

org.mockito.invocation.InvocationOnMock

when(client.deleteByQuery(anyString(), anyString())).then(invocationOnMock -> {
    assertEquals("myCollection", invocationOnMock.getArgument(0));
    assertThat(invocationOnMock.getArgument(1), Matchers.startsWith("id:"));
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • 3
    I'm not able to see how this is more convenient than the old way. I love good use of lambdas, but I'm not sure if this is one. – Eric Wilson Oct 15 '18 at 17:04
5

First of all: you should always import mockito static, this way the code will be much more readable (and intuitive) - the code samples below require it to work:

import static org.mockito.Mockito.*;

In the verify() method you can pass the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:

ArgumentCaptor<MyExampleClass> argument = ArgumentCaptor.forClass(MyExampleClass.class);
verify(yourmock, atleast(2)).myMethod(argument.capture());

List<MyExampleClass> passedArguments = argument.getAllValues();

for (MyExampleClass data : passedArguments){
    //assertSometing ...
    System.out.println(data.getFoo());
}

The list of all passed arguments during your test is accessible via the argument.getAllValues() method.

The single (last called) argument's value is accessible via the argument.getValue() for further manipulation / checking or whatever you wish to do.

fl0w
  • 3,593
  • 30
  • 34