user1539343
user1539343

Reputation: 1669

Mockito and unit testing - how to control new object creation

I have this method to be unit tested:

public class DPService {
    public DPModel saveTreeRecursively(DPDTO dpDTO) {
        DPModel dpModel = new DPModel(dpDTO.getDPKey(), dpDTO.getName());
        DPModel savedDpModel = dpDAO.save(dpModel);
        Long dpId = savedDPModel.getDpId();

        // after some operations
        return savedDpModel;
    }
}

The test class is:

public class DPServiceTest {
    @Test
    public void testSaveTreeRecursively() {
        DPModel dpModel1 = new DPModel(dpKey, dpName); // same dpKey and dpName 
        //used in the SUT method to create DPModel, dpModel

        DPModel dpModel2 = new DPModel(dpKey, dpName);
        dpModel2.setDPId(123L);

        // SUT
        DPService dpService = new DPService();

        // creating a mock DAO so that, the unit testing is independent of real DAO
        DPDaoMock dpDaoMock = Mockito.mock(DPDao.class);

        // we want to control the mock dpDAO so that it returns 
        // the model we want that the below SUT method uses; basically we are pretending that
        // the dpDAO saved the dpModel1 with a primary key, dpId = 123
        // and returned the dpModel2 saved in the database.
        Mockito.when(dpDaoMock.save(dpModel1)).thenReturn(dpModel2);

        DPModel dpModel3 = dpService.saveTreeRecursively(dpDTO);

        assertEquals(dpModel3.getDpID(), 123L);
    }
}

So obviously the SUT method failed at line:

Long dpId = savedDPModel.getDpId();

because the instance created inside the SUT method is not the same one we want to be used from the dpDaoMock.

So how can I overcome this problem? Is there any other better approach to mock DAO?

Thanks

Upvotes: 3

Views: 2779

Answers (1)

Some of the options.

Abstract factory

The factory interface of DPModel can be introduced as a dependency of DPService. So that, the return value of the factory method (of the factory) can be mocked and used for the assertion.

Please refer to the Abstract factory pattern.

Matcher

Mockito matchers can be used to check arguments of mock methods:

Mockito.when(dpDaoMock.save(Matchers.any())).thenReturn(dpModel2);

or more strict example:

Mockito.when(dpDaoMock.save(Matchers.argThat(new ArgumentMatcher<DPModel>() {
    @Override
    public boolean matches(Object argument) {
        DPModel dpModel = (DPModel) argument;
        return dpModel.getDpId().equals(123L);
    }
}))).thenReturn(dpModel2);

Upvotes: 2

Related Questions