Can Mockito verify an argument has certain properties/fields?

In Mockito 2.1.0 and up with Java 8 you can pass the lambda to argThat out of the box so that one does not need a custom argument matchers. For the example in the OP would be:

verify(mockedFoo).doThing(argThat((Bar aBar) -> aBar.getI() == 5));

This is because as of Mockito 2.1.0, ArgumentMatcher is a functional interface.


If you are using Mockito 2.1.0 or above and Java 8 or above, see this answer instead, it's much simpler now.


I found the answer while writing the question.

Yes, you can. Instead of using any(Bar.class) you'll need to implement your own instance of ArgumentMatcher<T> and use Mockito#argThat(Matcher), for example, say we want to check that i is 5...

// in the test (could also be outside)

private static final class BarIs5 extends ArgumentMatcher<Bar> {
  
  @Override
  public boolean matches(Object argument) {
    return ((Bar) argument).getI() == 5;
  }
}

Then verify like so: verify(mockedFoo).doThing(argThat(new BarIs5()));


Kick it up a notch by adding constructor parameters!

private static final class BarIsWhat extends ArgumentMatcher<Bar> {
  
  private final int i;

  public BarIsWhat(int i) {
    this.i = i
  }

  @Override
  public boolean matches(Object argument) {
    return ((Bar) argument).getI() == i;
  }
}

Then verify like so: verify(mockedFoo).doThing(argThat(new BarIsWhat(5)));


Update: This popped in my queue because of a badge and saw some room for improvement.

I have tried this and it works. You can sort of use a lambda expression which is a lot cleaner (if you don't mind unchecked cast warnings at least).

The only issue is that argThat accepts a Hamcrest Matcher which is not a @FunctionalInterface. Luckily, Mockito's ArgumentMatcher is an abstract class that extends it and only has a single abstract method.

In your test (or some common location) make a method like below

private static <T> ArgumentMatcher<T> matches(Predicate<T> predicate) {
  return new ArgumentMatcher<T>() {

    @SuppressWarnings("unchecked")
    @Override
    public boolean matches(Object argument) {
      return predicate.test((T) argument);
    }
  };
}

Now, in your test you can do this to use a lambda expression:

verify(mockedFoo).doThing(argThat(matches( (Bar arg) -> arg.getI() == 5 )));