7

I have created a ArgumentMatcher,

private class IsListOf2Elements implements ArgumentMatcher<List<String>>{
    @Override
    public boolean matches(List<String> argument) {
        return ((List<String>)argument).size()==2;
    }
}

I want to negate this match, so match when size is not 2,

Mockito.doReturn(false).when(mock).addAll(Mockito.argThat(AdditionalMatchers.not(new IsListOf2Elements())));

But this is not correct. I get,

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
No matchers found for additional matcher Not(?)
-> at my.test.own.Mockito_aTest.test4e(Mockito_aTest.java:136)
ericj
  • 2,138
  • 27
  • 44

4 Answers4

6

For reference, be aware that Hamcrest matchers and Mockito matchers behave very differently. Hamcrest's stateless Matcher objects represent the match function as an instance, and can be wrapped to invert their results; Mockito's "registered matchers" work only via side-effects.

argThat adapts a Hamcrest matcher into a Mockito matcher, Hamcrest's CoreMatchers.not inverts a Hamcrest matcher, and Mockito's AdditionalMatchers.not inverts a Mockito matcher (via side-effects). This is part of the reason that CoreMatchers.not always returns a Matcher<T>, while AddionalMatchers.not returns an arbitrary T; it's operating on Mockito state you can't see.

This gives you the following behavior:

// BAD: Don't use AdditionalMatchers to invert a Hamcrest matcher.
doReturn(false).when(mock).addAll(
    Mockito.argThat(AdditionalMatchers.not(new IsListOf2Elements())));

// GOOD: Use AdditionalMatchers to invert a Mockito matcher. (See ericj's answer.)
doReturn(false).when(mock).addAll(
    AdditionalMatchers​.not(Mockito.argThat‌​(new IsListOf2Elements())));

// ALSO GOOD: Use CoreMatchers to invert a Hamcrest matcher. (See troig's answer.)
doReturn(false).when(mock).addAll(
    Mockito.argThat‌​(CoreMatchers.not(new IsListOf2Elements())));

If the exception you're making is about stubbed behavior, you can also use a more-specific override to stub the general behavior in addition to the specific exception.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
2

It seems to be that you cannot use a custom matcher as AdditionalMatchers.not method parameter.

However, you can use hamcrest org.hamcrest.CoreMatchers instead. This should work:

Mockito.doReturn(false).when(mock).addAll(Mockito.argThat(CoreMatchers.not(new IsListOf2Elements())));

Hope it helps

troig
  • 7,072
  • 4
  • 37
  • 63
  • Strange, It worked well for me. Maybe a versions issue, because ArgumentMatcher in my Mockito version (1.9.5) is an abstract class, not an interface like in your OP. Which versions are you using? – troig Oct 25 '16 at 06:28
  • I resolved it. You have to switch: `Mockito.doReturn(false).when(mock).addAll(AdditionalMatchers.not(Mockito.argThat(new IsListOf2Elements())));` – ericj Oct 25 '16 at 06:56
  • Great! and thanks for letting me know. You should add your own answer and accept it. – troig Oct 25 '16 at 07:00
0

I found the answer myself. Turn is around,

Mockito.doReturn(false).when(mock).addAll(AdditionalMatchers‌​.not(Mockito.argThat‌​(new IsListOf2Elements())));

The reason is that AdditionalMatchers‌​.not expects a registered matcher, and Mockito.argThat‌ does do that.

ericj
  • 2,138
  • 27
  • 44
0

Just make this:

AdditionalMatchers.not(ArgumentMatchers.eq(...)
Marcus Voltolim
  • 413
  • 4
  • 12