Nikhil
Nikhil

Reputation: 2883

java mocking custom objects

public class MainClass  {

    public void makeCall() {
        CustomObject obj = new CustomObject();
        obj.testMethod();
    }
}

I want to unit test the makeCall(). So i have to mock the CustomObject in the above sample. I am using Mockito as the mock framework.But when i mock the object like mock(CustomObject.class). makeCall() method always call the actual object not the mocked one.Is there anyway to mock the local objects. Please help

Upvotes: 3

Views: 7432

Answers (3)

fge
fge

Reputation: 121710

Not with Mockito proper, no. You have to modify your code so that you create your custom object from another source and mock that source.

This is what I'd recommend... However there does exist a solution with PowerMockito:

final CustomObject obj = mock(CustomObject.class);

PowerMockito.whenNew(CustomObject.class).withNoArguments()
    .thenReturn(obj);

However, uh. Refactor your code. You'll be all the better for it.

Upvotes: 0

Adam Arold
Adam Arold

Reputation: 30528

Short answer is no. What you can do is to refactor the local object to a field or a parameter like this:

public class MainClass  {

    public void makeCall(CustomObject obj) {
        obj.testMethod();
    }
}

Your current program violates the Dependency Inversion Principle so it is advised to refactor it anyway.

If you make the field an instance variable you can mock it easily if you have a setter or you initialize it based on a constructor parameter. Example for the latter:

public class MyTest {

    @Mock
    private CustomObject objMock;

    private MyClass objToTest;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        objToTest = new MyClass(objMock);
    }

}

Upvotes: 1

Adrian Shum
Adrian Shum

Reputation: 40036

A unit-test-friendly version of your MainClass should have CustomObject injected, for example:

public class MainClass  {
    private CustomObject customObject = new CustomObject();  // a default one if none is provided

    public void setCustomObject(CustomObject customObject) {
        this.customObject = customObject;
    }

    public void makeCall() {
        this.customObject.testMethod();
    }
}

and your test will look like:

CustomObject mockCustomObject = mock(CustomObject.class);
when(mockCustomObject.testMethod()).thenReturn(...);

MainClass sut = new MainClass();
sut.setCustomObject(mockCustomObject);

sut.makeCall();

verify(mockCustomObject).testMethod();

With Mockito's annotation, it can be further simplified as:

public class MyClassTest {
    @InjectMocks
    private MainClass mainClass;

    @Mock
    private CustomObject mockCustomObject;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);  // or use mockito runner
    }

    @Test
    public void testMakeCall() {
        when(mockCustomObject.testMethod()).thenReturn(...);
        mainClass.makeCall();
        verify(mockCustomObject).testMethod();
    }
}

Upvotes: 4

Related Questions