spring-test-dbunit
提供了 Spring 与 DbUnit 的集成,在 Spring 中我们可以使用注解来进行数据的准备和清理。
为了使用 DbUnit 的注解,我们需要使用 DbUnitTestExecutionListener
类,下面是典型的使用 JUnit 4 的注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
完成配置后,我们需要使用的注解是 @DatabaseSetup
和 @DatabaseTearDown
来进行数据库的数据初始化和重置。
下面是典型的注解使用,这里我们使用 sampleData.xml
作为数据文件,这个文件通常在测试类的同一个包下。
@DatabaseSetup("sampleData.xml")
你也可以使用其它路径,如
@DatabaseSetup("/META-INF/dbtest/sampleData.xml")
默认情况下,初始化的时候会进行 CLEAN_INSERT
操作,这意味着所有在数据文件,即这里的 sampleData.xml
中的表的数据,在插入数据时会被删除。这个是 DBUnit 的其中一个行为,详细的参考 DBUnit 的文档。
@DatabaseTearDown
注解用来在测试完成之后重置数据,与 @DatabaseSetup
类似,可以使用在类上或方法上,它们有一样的属性可以设置。
注意:如果你将此注解与 @Transactional
一起使用,你可能需要更改配置。下面会有相应解释。
@ExpectedDatabase
用来验证数据库的数据是否和期待的一样。比如当我们插入或删除数据的时候,就很有用。这个注解可以使用在类或方法上,当在类上使用时,每一个测试方法都会进行数据比较。
用法:
@ExpectedDatabase("expectedData.xml")
@ExpectedDatabase
支持两种不同的模式,DatabaseAssertionMode.DEFAULT
是默认的模式,它比较整个数据库。DatabaseAssertionMode.NON_STRICT
会忽略没有在期待的数据集文件中出现的表或列。通常后一种模式是常用的,因为我们的方法通常情况下只会影响几个表或几个列。
如果你一同使用了 DbUnitTestExecutionListener
和 TransactionalTestExecutionListener
你可能会遇到与事务相关的问题。比如事务没有开始或在数据验证之前进行了回滚等。为了在 DBUnit 中使用事务,我们应该使用 TransactionDbUnitTestExecutionListener
。
修改后的配置如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class })
事务会在 @DatabaseSetup
之前启动,在 @DatabaseTearDown
和 @ExpectedDatabase
之后结束。
我们有两个服务类:
StudentService
学生服务类
ClazzService
班级服务类
ClazzService
有一个删除方法,删除班级时,先删除该班级下的所有学生
@Transactional
public void delete(Long id) {
studentService.deleteByClazzId(id);
clazzDao.delete(id);
}
下面的例子针对这个方法进行测试。
setup.xml
,这里是 dbunit 的 FlatXmlDataSet 格式,元素名代表表名,属性对应字段名。<?xml version="1.0" encoding="utf-8" ?>
<dataset>
<student id="1" name="student1" clazz_id="1"/>
<student id="2" name="student2" clazz_id="2"/>
<clazz id="1" name="clazz1"/>
<clazz id="2" name="clazz2"/>
</dataset>
假设我们删除了班级 id 为 1 的班级,则我们期待的数据库数据为 delete-result.xml
<?xml version="1.0" encoding="utf-8" ?>
<dataset>
<student id="2" name="student2" clazz_id="2"/>
<clazz id="2" name="clazz2"/>
</dataset>
ClazzServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context.xml")
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class})
public class ClazzServiceTest {
@Autowired ClazzService clazzService;
@Test
@Transactional
@DatabaseSetup("setup.xml")
@ExpectedDatabase("delete-result.xml")
public void testDelete() {
clazzService.delete(1L);
}
}
有时候我们对多个方法进行测试的时候,对数据库进行了多次删除、插入操作的时候,@Transactional
能使数据库数据回滚,但是自增字段不会重设,这时候对我们的测试就会造成干扰,因为我们无法确定下一次插入数据时自增字段的值。关于这个问题参考 这篇博文