Search code examples
javamockitojunit5verifyargument-matcher

Mockito argThat does not work when used to match an iterator arg


I am trying to verify a mocked service was called with an arguments in which the last is an iterator. This is the assertion in the test:

verify(myService).myMethod(
    ...,
    argThat(dataIterator -> iteratorEquals(dataIterator, dataToSave.iterator())));

and I have this TestHelper method:

public class TestHelpers {

    public static <T> boolean iteratorEquals(Iterator<T> x, Iterator<T> y) {
        while (x.hasNext() && y.hasNext()) {
            if (x.next() != y.next()) {
                return false;
            }
        }
        return x.hasNext() == y.hasNext();
    }
}

I was debugging the static method and it seems like the value returned from it is indeed true. Also, when debugging I can see the arguments passed to the service are as expected, but the assertion for some reason will fail in this case. When I am changing the assertion to this:

verify(myService).myMethod(
    ...,
    any());

the test will pass, meaning the problem is, indeed, with the iterator argument. This is the error I receive when the test fails:

myService.myMethod( ..., <custom argument matcher> ); Wanted 1 time: -> at ...(StorageClientTest.java:91) But was 0 times.

org.mockito.exceptions.verification.TooFewActualInvocations: myService.myMethod( ..., <custom argument matcher> ); Wanted 1 time: -> at ...(StorageClientTest.java:91) But was 0 times.

Am I doing something wrong here? why does the test fail?


Solution

  • The solution to this issue is to change the signature of the generic help method to return ArgumentMatcher and to move the lambda expression inside it:

    public <T> ArgumentMatcher<Iterator<T>> equalsIterator(Iterator<T> compareTo) {
        return x -> {
            while (x.hasNext() && compareTo.hasNext()) {
                if (x.next() != compareTo.next()) {
                    return false;
                }
            }
            return x.hasNext() == compareTo.hasNext();
        };
    }
    

    and I am calling it this way:

    verify(myService).myMethod(
        ...,
        argThat(equalsIterator(dataToSave.iterator())));