Mock a method call from another class

Ash picture Ash · May 8, 2015 · Viewed 10k times · Source

My code structure :

class A {
    void methodA() {
        //some code
        B b = new B();
        response = b.methodB(arg1, arg2);
        //some code using "response"
    }
}

I am UNIT testing class A and don't want to actually call methodB(). Is there any way to mock this method call by a custom response. I tried Mockito to mock this method call as below:

B classBMock = Mockito.mock(B.class);
Mockito.when(classBMock.methodB(arg1, arg2)).thenReturn(customResponse);
A objA = new A();
objA.methodA();

On calling methodA() the above way I don't get customResponse when methodB() is called within A. But when I call methodB() with classBMock, I get the customResponse. Is there anyway I can get customResponse from methodB() while calling methodA().

Answer

Mureinik picture Mureinik · May 8, 2015

One common way of doing this is extracting the creating of the collaborator instance to a method, and spying the class you want to test.

In this case, you could rewrite A like this:

public class A {
    public B createB() {
        return new B();
    }

    public void methodA() {
        //some code
        B b = createB();
        response = b.methodB(arg1, arg2);
       //some code using "response"
    }
}

Now your test can spy the A instance you're testing, and inject a mock for B:

B classBMock = Mockito.mock(B.class);
Mockito.when(classBMock.methodB(arg1, arg2)).thenReturn(customResponse);
A objA = Mockito.spy(new A());
Mockito.when(objA.createB()).thenReturn(classBMock());
objA.methodA();


Edit:
If you cannot modify A, another way to go could be to use PowerMock. Note that this code snippet shows only the relevant mocking, and doesn't display the annotations required to allow PowerMock to instrument your class:

B classBMock = Mockito.mock(B.class);
Mockito.when(classBMock.methodB(arg1, arg2)).thenReturn(customResponse);
PowerMockito.whenNew(B.class).withNoArguments().thenReturn(classBMock);
A objA = new A();
objA.methodA();