Mockito in real world: ArgumentMatcher and ArgumentCapture

 Mockito really helps when you want to make white box testing. In addition to testing the results of some code, you can make sure that the code makes necessary method calls during its execution. 

For example, the following method prints the current time:

public MyClass {
  public void printTime(PrintStream ps) {
    ps.print("Current time is: ");
    Date now=new Date();
    SimpleDateFormat sdf=new SimpleDateFormat("hh:mm");
    ps.print(sdf.format(now));
  }
}

Let's try to test this code. We want to make sure the code calls PrintStream 2 times, ignore the first call and check that the second one is in correct format: two digits, colon(:) and another two digits.

I started with writing a custom ArgumentMatcher just to check there is a semicolon in a string:

class SemicolonMatcher implements ArgumentMatcher<String> {
  public boolean matches(String s) {
    return s.contains(":");
  }
}

If you write the test in most simple form:

PrintStream ps=mock(PrintStream.class);
new MyClass().printTime(ps);
verify(ps).print("Current time is: ");
verify(ps).print(argThat(new SemicolonMatcher()));
}

This test will fail. The first verify() will succeed, but the second will grab all the invocations of print(), including the first invocation with "Current time is: ".

org.mockito.exceptions.verification.TooManyActualInvocations: 
printStream.print(<Semicolon matcher>);
Wanted 1 time:
-> at .....
But was 2 times. Undesired invocation:
-> at ....

That was weird. I'd expect every verify worry only on 1 invocation, the same way the verify() with simple arguments checks only 1 invocation.

Anyway, to create a working test, you can use ArgumentCapture:

PrintStream ps=mock(PrintStream.class);
new MyClass().printTime(ps);
ArgumentCaptor<String> captor=ArgumentCaptor.forClass(String.class);
verify(ps, times(2)).print(captor);
assertTrue(captor.getAllValues().get(1).contains(":"));

To my taste, this looks much less readable, but I could not find a better way to solve this problem.

In Mockito documentation it's said that you cannot combine simple arguments with mathchers in same verify(). But I did not find the explanation, why all invocations (of print() in my example) pass through the same verify() if I use the matchers. For me, it's very confusing.

If you have an idea how to combine simple arguments with matchers, please, please let me know.

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com