我在我的最新项目中使用了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));
}
测试看起来正常。您设置了fixture,执行了该方法,然后验证它是否按您的期望执行了。
如果您创建了一个实用程序类作为模拟工厂,则可以使其更具可读性。假设方法findByDescription(string)
是在类或接口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);
}
}
这种方法使您的测试更具可读性,并且您的mock可重用。只需确保工厂方法的名称描述了它们返回的模拟类型。如果您需要大量的模拟工厂方法,那么您应该创建多个实用程序类,每个实用程序类专用于一种类型的模拟。如DaoMockFactory
, CsvMockFactory
等
还有一件事:遵循一些命名约定是个好主意:
- 为每个主类设置一个测试类,例如
class TestService
为class Service
。 - 让单元测试方法以它正在测试的方法命名,例如方法
testSave()
测试方法save()
。