5

Trying to stub a class with 2 possible invocation/return paths using custom Matcher ... ran into an interest problem.

Here is a test I wrote to illustrate ...

This might be difficult to implement, but I would have expected the 1st ArgumentMatcher is not invoked when stubbing the second when(...).thenReturn(...)

But running the code below prints foobar on stdout. Is there anything we can do to prevent this behavior? Or am I using the wrong pattern by trying to stub a single mock with multiple custom ArgumentMatcher

FYI - powermock is on my classpath for other tests (not sure if that matters but I do see it in the stack trace)

import org.junit.Test;
import org.mockito.ArgumentMatcher;

import java.io.File;
import java.io.FilenameFilter;

import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MyTest {
    @Test
    public void name() throws Exception {
        File file = mock(File.class);
        when(file.list(argThat(new ArgumentMatcher<FilenameFilter>() {
            @Override
            public boolean matches(Object argument) {
                System.out.println("foobar");
                return 1 + 1 >2;
            }
        }))).thenReturn(null);
        // at this point, mockito will attempt to run the previous matcher, treating this stub code as invocation ... and printing out 'foobar'
        when(file.list(argThat(new ArgumentMatcher<FilenameFilter>() {
            @Override
            public boolean matches(Object argument) {
                System.out.println("barbar");
                return true;
            }
        }))).thenReturn(null);

    }
}

EDIT added comments to help illustrate

echen
  • 2,002
  • 1
  • 24
  • 38

1 Answers1

5

If you use the doReturn() syntax, then the method is not called.

doReturn(null).when(file).list(argThat(new ArgumentMatcher<FilenameFilter>() {
    @Override
    public boolean matches(Object argument) {
        System.out.println("barbar");
        return true;
    }
}));

See this answer for more details. Also, the docs explain this use-case (emphasis mine):

You can use doReturn(), [...] in place of the corresponding call with when(), for any method. It is necessary when you:

  • stub void methods
  • stub methods on spy objects (see below)
  • stub the same method more than once, to change the behaviour of a mock in the middle of a test.
Community
  • 1
  • 1
nickb
  • 59,313
  • 13
  • 108
  • 143