Mockito和单元测试 - 如何控制新对象的创建

时间:2016-10-08 23:55:27

标签: java junit mockito

我有这种方法进行单元测试:

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;
    }
}

测试类是:

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);
    }
}

很明显,SUT方法失败了:

Long dpId = savedDPModel.getDpId();

因为在SUT方法中创建的实例与我们想要在dpDaoMock中使用的实例不同。

那我怎么能克服这个问题呢?还有其他更好的方法来模拟DAO吗?

由于

1 个答案:

答案 0 :(得分:1)

一些选项。

抽象工厂

DPModel的工厂界面可以作为DPService的依赖项引入。这样,工厂方法(工厂的)的返回值可以被模拟并用于断言。

请参阅Abstract factory pattern

匹配器

Mockito匹配器可用于检查模拟方法的参数:

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

或更严格的例子:

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);