Mockito: "Argument should be a mock, but is" error when combine @InjectMocks with @Spy

Created on 21 Aug 2015  路  4Comments  路  Source: mockito/mockito

In mockito <=2.0.12 there was possible to use @InjectMocks on spy object, but seems like this was changed since 2.0.13-beta version:

Argument should be a mock, but is: class mockito.bug.snippet.ArgumentShouldBeAMockButIsTest$B

Test case:

package mockito.bug.snippet;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

public class ArgumentShouldBeAMockButIsTest {

    // Inject here
    static class A {
        private B b;
    }

    // Inject here also
    static class B {
        private C c;
    }

    // Some dependency
    static class C {
    }

    @InjectMocks
    private final A a = new A();

    @Spy
    @InjectMocks
    private final B b = new B();

    @Mock
    private C c;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    // Worked in 2.0.12-beta
    public void testArgumentShouldBeAMockButIsNonMock() {
        b.toString();
    }
}
bug maybe ready

Most helpful comment

So what is Mockito official stance on using @InjectMocks with @Spy? The javadoc still references it as being supported (https://github.com/mockito/mockito/blob/release/3.x/src/main/java/org/mockito/InjectMocks.java#L140) but it doesn't work by using both annotations on a field. I don't mind doing the workaround mentioned above with Mockito.spy(new B()) instead of the annotations while this bug is being fixed but I'd like a definitive answer since that bug has been opened for a while now!

Thanks!

All 4 comments

Using the real objects PR, I was able to create a fix for it.

The problem was an internal name-retrieval of mocks during injection to fix a previous issue. The commit that caused this bug was: https://github.com/mockito/mockito/commit/110ffa80070bf54ab8efabdaaa27b193a93d6128

Looking at that again it seems the use case is a bit adge case, and worked by chance, Mockito injection was never designed to support complicated injection stuff, like building a graph.

I've just noticed that there is still this misbehavior (undocumented feature) when you provide spy object by hand. If you run test provided by @vbuell with object created by Mockito#spy method then test passes (of course it's not important if there is @Spy annotation on that field).

I've reproduced this issue on latest Mockito version: 2.7.14

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

public class ArgumentShouldBeAMockButIsTest {

    // Inject here
    static class A {
        private B b;
    }

    // Inject here also
    static class B {
        private C c;
    }

    // Some dependency
    static class C {
    }

    @InjectMocks
    private final A a = new A();

    @Spy
    @InjectMocks
    private final B b = Mockito.spy(new B());

    @Mock
    private C c;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    //Test passed
    public void testArgumentShouldBeAMockButIsNonMock() {
        b.toString();
    }
}

So what is Mockito official stance on using @InjectMocks with @Spy? The javadoc still references it as being supported (https://github.com/mockito/mockito/blob/release/3.x/src/main/java/org/mockito/InjectMocks.java#L140) but it doesn't work by using both annotations on a field. I don't mind doing the workaround mentioned above with Mockito.spy(new B()) instead of the annotations while this bug is being fixed but I'd like a definitive answer since that bug has been opened for a while now!

Thanks!

Was this page helpful?
0 / 5 - 0 ratings