611

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?

6 Answers 6

1055

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()); 
Sign up to request clarification or add additional context in comments.

6 Comments

Can you capture the arguments passed to doSomething() in each separate invocation with this?
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 groups.google.com/forum/#!msg/mockito/KBRocVedYT0/5HtARMl9r2wJ.
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()) ?
If one needs to handle the case described by @asmaier, I posted an answer here: stackoverflow.com/a/36574817/1466267
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.
|
82

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

2 Comments

This is a nice technique. I'm currently getting some rather cryptic output though: "Wanted but not invoked: /n mockAppender.append( <Index manager u t$$ lambda$ 5 9/ 1 3 1 9 5 1 0 1 6> );" - the arg there is a CharSequence. Do you know of any way to get the report to print out the "wanted" arg properly?
@mikerodent The cryptic output can be fixed if you go the more verbose route of creating a class that implements ArgumentMatcher<T>. Overriding the toString method in your implementation will provide any message you want in the mockito test output.
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()); 

1 Comment

is there any way to capture both the values?
29

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

Comments

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

1 Comment

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.
7

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.