I am facing with issue where I need to track invocation of some method but only with specified argument parameter. See issue below
@Test
public void simpleTest() {
ArgumentCaptor<Pear> captor = ArgumentCaptor.forClass(Pear.class);
Action action = mock(Action.class);
action.perform(new Pear());
action.perform(new Apple());
verify(action, times(1)).perform(captor.capture());
}
static class Action {
public void perform(IFruit fruit) {}
}
static class Pear implements IFruit {}
static class Apple implements IFruit {}
interface IFruit {}
But getting :
org.mockito.exceptions.verification.TooManyActualInvocations:
action.perform(<Capturing argument>);
Wanted 1 time:
But was 2 times. Undesired invocation:
..
What I am doing wrong? Mockito v 1.10
To be honest it is just for example and my code more complicated and I don't know, how many times perform will be invoked with Apple.class. It doesn't matter for me. I need to verify only call of perform(Pear.class)
UPD: I need to verify that method with Pear.class was called once. Lets imagine that Action is Transaction and perform is save(DomainObject). So I need to be sure that save(MyDomainObject) was called once, but no matter how many Objects were saved before. This action is atomic for Test and I can't reset mock between these operations
Mockito ArgumentCaptor is used to capture arguments for mocked methods. ArgumentCaptor is used with Mockito verify() methods to get the arguments passed when any method is called. This way, we can provide additional JUnit assertions for our tests.
It is used to capture argument values for further assertions. We use argument captor with the methods like verify() or then() to get the values passed when a specific method is invoked. It is used to capture the method arguments. It is used to build a new ArgumentCaptor.
The first way to create the argument captor is to use annotation @Captor declared on field. If you are using JUnit 4, you can initialize it with Mockito JUnit Runner. @RunWith(MockitoJUnitRunner. class) public class MockitoArgumentCaptorTest { @Captor private ArgumentCaptor<String> stringCaptor; ... }
Mockito allows us to create mock objects and stub the behavior for our test cases. We usually mock the behavior using when() and thenReturn() on the mock object.
To verify the number of calls with Pear
instances parameters, you may use :
verify(action, times(1)).perform(isA(Pear.class));
Cf. Mockito. Verify method param to be a paticular class
Note that since Mockito 2.1, the following would also work :
verify(action, times(1)).perform(any(Pear.class));
cf. public static T any(Class type)
...This is an alias of: isA(Class)...
...Since mockito 2.1.0 any() and anyObject() are not anymore aliases of this method.
Workaround using a custom captor class
@Test
public void simpleTest() {
MyArgumentCaptor pearCaptor = new MyArgumentCaptor(Pear.class);
Action action = mock(Action.class);
action.perform(new Pear());
action.perform(new Apple());
verify(action, times(1)).perform((IFruit) argThat(pearCaptor));
System.out.println(pearCaptor.getMatchedObj());
}
class MyArgumentCaptor extends InstanceOf {
private Object matchedObj;
MyArgumentCaptor(Class<?> clazz) {
super(clazz);
}
@Override
public boolean matches(Object actual) {
boolean matches = super.matches(actual);
if (matches) {
matchedObj = actual;
}
return matches;
}
Object getMatchedObj() {
return matchedObj;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With