Ira Re
Ira Re

Reputation: 790

How to mock methods called by method under the test

I'm working with legacy code and would like to increase the test coverage for it.

I have a class like:

public class MyStrategy implements SomeStrategy {

    TimeAndDateUtils timeAndDateUtils = new TimeAndDateUtils();

    @Override
    public boolean shouldBeExtracted(Argument argument) {
        Date currentDate = timeAndDateUtils.getCurrentDate();
        return currentDate.isBefore(argument.getDate());
    }

}

I would like to test the shouldBeExtracted-Method an mock the call to timeAndDateUtils.getCurrentDate() so that it returns some fixed value.

So what I'm trying to do is:

Date currentDate = %some fixed date%
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);
Assert.assertTrue(myStrategy.shouldBeExtracted(argument))

How can I force the MyStrategy-Class to use the mocked object instead of creating it's own?

Upvotes: 0

Views: 995

Answers (4)

Nicolas Filotto
Nicolas Filotto

Reputation: 44965

Assuming that you cannot rewrite the existing code to make it more testable, this is the typical use case for the annotation @InjectMocks allowing to inject mock or spy fields into tested object automatically.

@RunWith(MockitoJUnitRunner.class)
public class MyStrategyTest {
    @Mock
    private TimeAndDateUtils timeAndDateUtils;

    @InjectMocks
    private MyStrategy myStrategy;

    @Test
    public void testShouldBeExtracted() {
        ...
        Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);
        Assert.assertTrue(myStrategy.shouldBeExtracted(argument));
    }
}

Upvotes: 1

kimy82
kimy82

Reputation: 4475

Mockito has a nice class for overriding private objects inside a class. It is called WhiteBox. It works like this

MyStrategy myStrategy = new MyStrategy();
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Whitebox.setInternalState(myStartegy, "timeAndDateUtils", timeAndDateUtilsMock);

That will change your TimeAndDateUtils for your mock

Upvotes: 0

Nkosi
Nkosi

Reputation: 247088

timeAndDateUtils is being created in the class itself which make it difficult to access for test. inject the dependency via constructor so that a mock can be created

public class MyStrategy implements SomeStrategy {

    TimeAndDateUtils timeAndDateUtils;

    public MyStrategy(TimeAndDateUtils timeAndDateUtils) {
        this.timeAndDateUtils = timeAndDateUtils;
    }

    @Override
    public boolean shouldBeExtracted(Argument argument) {
        Date currentDate = timeAndDateUtils.getCurrentDate();
        return currentDate.isBefore(argument.getDate());
    }

}

Test

//Arrange
Date currentDate = %some fixed date%
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);

MyStrategy myStrategy = new MyStrategy(timeAndDateUtils);

//Act 
bool result = myStrategy.shouldBeExtracted(argument);

//Assert
Assert.assertTrue(result);

Upvotes: 0

Piotr Sołtysiak
Piotr Sołtysiak

Reputation: 1006

You can use reflection to put mock into MyStrategy object. It would look like this:

MyStrategy myStrategy = new MyStrategy(); // I don't know if you are using DI
MyStrategy.class.getDeclaredField("timeAndDateUtils").set(myStrategy, timeAndDateUtilsMock);

Upvotes: 1

Related Questions