Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stubbing a void method with side effects

How can we replace the method body of a void method of a stub?

Something like this:

interface Foo {
    void foo(Integer j);
}

(...)

Foo mockFoo = mock(Foo.class);

Answer<Void> ans = invocation -> {
            Object[] args = invocation.getArguments();
            System.out.println("called with arguments: " + Arrays.toString(args));
            return null;
        };

when(mockFoo.foo(any())).thenAnswer(ans);

(...)

mockFoo.foo(5) // Should print out "called with arguments: [5]"

It is important to be able to access the parameters, and to be able to execute some code that uses those parameters.

We tried doAnswer(ans).when(mockFoo).foo(any());, but it seems to execute the body of the ans lambda a few times when setting up the mock, and it resets our mockFoo variable to "null" for some weird reason between the .when(mockFoo) and the .foo(any()) calls.

So effectively:

Foo mockFoo = mock(Foo.class)
// mockFoo is an instance of a Foo$MockitoMock

Foo o = doAnswer(ans).when(mockFoo);
// mockFoo just became null at this point..?!
o.foo(any());

P.S. We are using the VertxUnitRunner for running the test, but the problem persists with the MockitoJUnitRunner as well.

like image 667
Ákos Vandra-Meyer Avatar asked Oct 30 '22 15:10

Ákos Vandra-Meyer


1 Answers

Resolved in comments:

You were right. In my actual test I was supplying any() as parameter for an int, which seems to have been the cause. Replacing it with anyInt() fixed the problem.

This is difficult to warn about, because the exception comes from Mockito's default null value (necessary due to erasure) being automatically unboxed (necessary due to Java 5+ semantics), which is outside of Mockito's control and prior to Mockito knowing which method signature your test is attempting to call. This is also not a Mockito exception, or even an exception that Mockito deliberately invokes, so the error message is difficult to modify with suggestions.

For all uses of Mockito matchers in primitive values, use the appropriate primitive: anyInt, intThat, and so forth.

like image 130
Jeff Bowman Avatar answered Nov 09 '22 17:11

Jeff Bowman