Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito counting stubbing as invocation

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

like image 230
echen Avatar asked Dec 02 '16 17:12

echen


People also ask

What is stubbing in Mockito?

A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.

Why is my mock returning NULL?

If a method return type is a custom class, a mock returns null because there is no empty value for a custom class. RETURN_MOCKS will try to return mocks if possible instead of null . Since final class cannot be mocked, null is still returned in that case.

What does thenReturn do in Mockito?

thenReturn or doReturn() are used to specify a value to be returned upon method invocation. //”do something when this mock's method is called with the following arguments” doReturn("a").

What is doAnswer Mockito?

Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call. Use doAnswer() when you want to stub a void method with generic Answer .


1 Answers

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.
like image 86
nickb Avatar answered Sep 20 '22 15:09

nickb