user1471283
user1471283

Reputation: 381

Nested method mocking in Mockito

I have the following Java classes:

public class A
{
    @Autowired
    private B b;
    public int aFn()
    {
        int something = b.bFn();
    }
}
public class B
{
    @Autowired
    private C c;
    public int bFn()
    {
        int something = c.cFn();
    }
}
public class C
{
    public int cFn()
    {
        return 231;
    }
}

And the following test using Mockito to test the above code:

public class test
{
    @Autowired
    private A a;

    private C c;

    @Test
    public void testA()
    {
        c = mock(C.class);
        when(c.cFn(),anyInt()).thenReturn(something);
        assertEquals(0, a.aFn());
    }
}

When I debug testA, I find that real c.Cfn() gets executed, not the mocked one. Is there anything what I am doing incorrectly here? Please help!

Upvotes: 6

Views: 14950

Answers (2)

Manojkumar Khotele
Manojkumar Khotele

Reputation: 1019

Forget whether what you want to mock is direct or nested. Think of it from Spring's philosophical point of view.

What you are essentially want to do is mock a bean.

In your case, you have to mock bean for Class c using @MockBean annotations.

@RunWith(SpringRunner.class)
public class Test {
...
@MockBean private C c;
...
}

Please refer this article for details.

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691685

First of all, you should always mock the direct dependencies of an object, and not its transitive dependencies. So you should mock B, and not C, to test A. Then you would write a unit test for B by mocking C.

Second: you're not injecting the mock anywhere in the unit test. What you should have is:

public class Test {

    // not autowired here
    private A a;

    private B mockB;

    @Test
    public void testA() {
        mockB = mock(B.class);
        when(b.bFn(), anyInt()).thenReturn(something);

        // the missing part: injecting the mock into the tested object
        a = new A(mockB);
        // or a = new A();
        //    a.setB(mockB);

        assertEquals(0, a.aFn());
    }
}

When you use mock(B.class), you get one mock instance of B. That doesn't mean that all the other instances of B will do what the mock does.

Mocking C to test A is a bad practice: unit tests should test one class in isolation of the others. But if you really want that, then create a mock C, create a B and inject the mock C inside it, then create an A and inject the B inside it.

A --> B --> mockC

Upvotes: 11

Related Questions