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

Java Mockito和单元测试-如何控制新对象的创建,java,junit,mockito,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 = savedDPMode

我将对该方法进行单元测试:

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吗

谢谢

一些选项

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

请参阅

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

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);
Mockito.when(dpDaoMock.save(Matchers.argThat)(new ArgumentMatcher()){
@凌驾
公共布尔匹配(对象参数){
DPModel DPModel=(DPModel)参数;
返回dpModel.getDpId().equals(123L);
}
}))).然后返回(dpModel2);

尝试这样模拟方法:Mockito.when(dpDaoMock.save(any(DPModel.class)),然后返回(dpModel2)。这确实是个好主意。但是,由于saveTreeRecursive被递归调用,并且期望另一个DTO,并且基于DTO的第二个实例,我们需要返回另一个带有另一个dataPointId主键的模型。那么Matchers可能是您的答案。回答得很好。我想我更喜欢matcher解决方案。谢谢