173

In Mockito documentation and javadocs it says

It is recommended to use ArgumentCaptor with verification but not with stubbing.

but I don't understand how ArgumentCaptor can be used for stubbing. Can someone explain the above statement and show how ArgumentCaptor can be used for stubbing or provide a link that shows how it can be done?

Community
  • 1
  • 1
Can't Tell
  • 12,714
  • 9
  • 63
  • 91
  • 1
    Super short & nice explanation here : https://dzone.com/articles/mockito-argumentcaptor-how-to-use-for-stubbing – Benj Jun 22 '18 at 10:05

3 Answers3

284

Assuming the following method to test:

public boolean doSomething(SomeClass arg);

Mockito documentation says that you should not use captor in this way:

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

Because you can just use matcher during stubbing:

when(someObject.doSomething(eq(expected))).thenReturn(true);

But verification is a different story. If your test needs to ensure that this method was called with a specific argument, use ArgumentCaptor and this is the case for which it is designed:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));
David Rawson
  • 20,912
  • 7
  • 88
  • 124
Rorick
  • 8,857
  • 3
  • 32
  • 37
  • Thanks for the answer. I have a question. In the third code block we know that true is returned only when **expected** is passed to doSomething. But when is true returned in the second code block? Or does someObject always return true for someMethod in that case? – Can't Tell Sep 06 '12 at 09:02
  • Hm, I believe you meant "But when is true returned in the *third* code block?". In third code block we just don't care for return value and let it be default one. For boolean it is `false`, not `true`. – Rorick Sep 06 '12 at 09:05
  • No I counted all grey background blocks as code blocks. Including the first one liner. I was referring to the line **when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);** – Can't Tell Sep 06 '12 at 09:08
  • Ah, sorry. Yes, in this case true will be returned always. – Rorick Sep 06 '12 at 10:08
  • 4
    not sure the reason to "not use with stubbing" is a simple reason. matchers don't give us the actual expected argument (just the type) and leads to being okay with tests passing despite arguments that might be wrong. – dtc May 20 '16 at 16:28
  • @dtc actually you can verify the value using Matchers when stubbing. For example just use `eq("yourExpectedStringValue")` as the parameter. – Maciej Mar 28 '18 at 11:54
  • i think whenever().thenAnswer{} is the equivalent to ArgumentCaptor now in Mockito-kotlin right ? could you give an example of it ? – j2emanue Dec 15 '18 at 08:34
  • About this line: when(someObject.doSomething(eq(expected))).thenReturn(true); If it would be possible to use eq(expected), you would have an expected value to match with. In that case you wouldn't need an argument matcher at all, because you could use the expected value also in the verification. Using any() when stubbing in combination with an argument captor in the verification makes more sense. – Stefan Mondelaers Aug 01 '19 at 12:00
  • Neither in stubbing or verify make the use of argument captor clear, I mean if that is the reason for the documentation suggesting not using it in stubbing, when you write something like "verify(someObject).doSomething(argCaptor.capture())" you are not really verifying anything but the type in that line as the capture works like an any() matcher so it has the same issue than doing it in stubbing, to really accomplish verification you need to add the assertion over the captured value, then it is the same if you do it in one place or the other, it is a matter of taste IMO – raspacorp Sep 02 '20 at 21:47
4

Hypothetically, if search landed you on this question then you probably want this:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

Why? Because like me you value time and you are not going to implement .equals just for the sake of the single test scenario.

And 99 % of tests fall apart with null returned from Mock and in a reasonable design you would avoid return null at all costs, use Optional or move to Kotlin. This implies that verify does not need to be used that often and ArgumentCaptors are just too tedious to write.

Aubergine
  • 5,862
  • 19
  • 66
  • 110
0

The line

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

would do the same as

when(someObject.doSomething(Matchers.any())).thenReturn(true);

So, using argumentCaptor.capture() when stubbing has no added value. Using Matchers.any() shows better what really happens and therefor is better for readability. With argumentCaptor.capture(), you can't read what arguments are really matched. And instead of using any(), you can use more specific matchers when you have more information (class of the expected argument), to improve your test.

And another problem: If using argumentCaptor.capture() when stubbing it becomes unclear how many values you should expect to be captured after verification. We want to capture a value during verification, not during stubbing because at that point there is no value to capture yet. So what does the argument captors capture method capture during stubbing? It capture anything because there is nothing to be captured yet. I consider it to be undefined behavior and I don't want to use undefined behavior.

  • Answering your question, argumentCaptor.capture() does capture the value that is passed to the stubbed method, this is useful for when you have something like: "someObject.doSomething(new OtherObject(4))" in that case the captor will get that OtherObject instance that you can then use to verify that a 4 was passed – raspacorp Sep 02 '20 at 21:35
  • @raspacorp argumentCaptor.capture() does capture the value that is passed to the stubbed method when used in a vertification method. It doesn't when used while stubbing (when method) because there is nothing to be captured at that time (the logic to be tested is not called yet). – Stefan Mondelaers Sep 18 '20 at 12:48
  • The declaration of a stub means a definition of a future method invocation that will match the stub definition, when you declare a stub and you use matchers, it means that it will try to match them in the future when the method is called, the same applies to captor, capture will operate when the stub is honored during the method execution, there is not an undefined behavior here. Yes it is cleaner to use it in a mockito verify call and it is the recommended approach for readability, but it works if used in stubs as well. – raspacorp Dec 14 '22 at 06:03