0

我在我的最新项目中使用了 TDD 方法。它对我来说是新的:)

我有一项服务可以将 CSV 记录保存到数据库中。它将检查值是否存在并在必要时添加 - 因此是多个 DAO。

下面是一个运行正常的测试 - 但是有人可以告诉我是否有更好的方法来写这个吗?感觉不对。

谢谢

@Test
public void loadTest() {
    //mock....all methods called in my save method
    Dao1 dao1 = mock(Dao1.class);
    when(dao1.findByDescription(anyString())).thenReturn(mock(Model1.class));
    Dao2 dao2 = mock(Dao2.class);
    when(dao2.findByDescription(anyString())).thenReturn(mock(Model2.class));
    Dao3 dao3 = mock(Dao3.class);
    when(dao3.findByDescription(anyString())).thenReturn(mock(Model3.class));
    Dao4 dao4 = mock(Dao4.class);

    RowFromCsv row = mock(RowFromCsv.class);
    when(row.getAttribute1()).thenReturn(new DateTime()); //otherwise test fails - nullpointerexception
    when(row.getAttribute2()).thenReturn(new DateTime());
    Csv csv = mock(Csv.class);
    when(csv.next()).thenReturn(row).thenReturn(null);

    //this is what im testing...
    Service load = new Service();
    load.setDao1(dao1);
    load.setDao2(dao2);
    load.setDao3(dao3);
    load.setDao4(dao4);
    load.save(csv);

    //save called ok...
    verify(dao4).createOrUpdate(any(Model4.class));
}
4

1 回答 1

1

测试看起来没问题。您设置了您的固定装置,执行该方法,然后验证它是否符合您的预期。

如果您创建了一个用作模拟工厂的实用程序类,则可以使其更具可读性。假设该方法findByDescription(string)是在 class 或 interface 中定义的BaseDao,您可以执行以下操作:

public class MockFactory {
    public static <D extends BaseDao,M> D mockDao(Class<D> daoClass, Class<M> modelClass) {
        D dao = mock(daoClass);
        M model = mock(modelClass);
        when(dao.findByDescription(anyString())).thenReturn(model));
        return dao;
    }

    public static Csv csvWithOneRecord() {
        RowFromCsv row = mock(RowFromCsv.class);
        when(row.getAttribute1()).thenReturn(new DateTime()); 
        when(row.getAttribute2()).thenReturn(new DateTime());
        Csv csv = mock(Csv.class);
        when(csv.next()).thenReturn(row).thenReturn(null);
    }
} 

这种方法使您的测试更具可读性并且您的模拟可重用。只需确保工厂方法具有描述它们返回的模拟类型的名称即可。如果您需要大量的工厂方法,那么您应该创建多个实用程序类,每个实用程序类专用于一种类型的模拟。即DaoMockFactoryCsvMockFactory

还有一件事:遵循一些命名约定是个好主意:

  • 每个主要课程都有一个测试课程,即class TestService.class Service
  • 以它正在测试的方法命名单元测试方法,即方法testSave()测试方法save()
于 2013-05-17T01:17:44.163 回答