百度百科:dbunit是一个基于junit扩展的数据库测试框架。
简言之,dbunit是为了在单元测试中,通过备份数据库、导入测试数据、回滚恢复数据库的手段,在不污染数据库的前提下完成一系列单元测试工作。
IDataSet
接口:用于操作表集合
ITable
接口:用于操作表数据集合
DatabaseOperation
类:对表数据执行一系列操作,比如刷新、删除、插入等
在没使用DBunit做单元测试之前,一般遵循junit的测试流程:
加入DBunit实际上只是在junit的流程中添加几步操作数据库的动作:
操作的流程不是固定的,具体还是要根据测试的逻辑来决定,如果能够加入事务特性进行单元测试可以大大精简流程
进入正题,这里使用的版本是:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.dbunitgroupId>
<artifactId>dbunitartifactId>
<version>2.5.3version>
<scope>testscope>
dependency>
初始化SQL脚本:
CREATE TABLE `db_unit_test` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
测试数据XML:
<dataset>
<db_unit_test id="1" name="张三"/>
<db_unit_test id="2" name="李四"/>
<db_unit_test id="3" name="王五"/>
dataset>
AbstractBaseTest
封装DBunit基本操作方法,包含初始化连接、关闭连接方法,备份数据、还原数据、导入数据和清空数据方法。其中AbstractBaseTest
继承了AbstractTransactionalJUnit4SpringContextTests
类的事务特性,可以方便使用事务回滚特性实现数据库0污染。
参考:https://www.cnblogs.com/wade-xu/p/4547381.html
/**
*
* 单元测试基类
* 封装DBunit相关操作方法
*
* https://www.cnblogs.com/wade-xu/p/4547381.html
* @author oyf
*/
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
//继承AbstractTransactionalJUnit4SpringContextTests会在方法执行完成后进行事务回滚,如果需要不回滚事务需要在方法上加上 @Rollbak(false)
public abstract class AbstractBaseTest extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired
private DataSource dataSource;
/**
* 数据库连接对象
*/
private static IDatabaseConnection conn;
/**
* 备份文件
*/
private File tempFile;
/**
* 文件跟目录
*/
public static final String ROOT_URL = "src/test/resources/";
// DBunit方法 --------------------------------------------------------
/**
* 获取数据库连接
* @throws Exception
*/
@Before
public void setup() throws Exception {
//get DataBaseSourceConnection
conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource));
}
/**
* 关闭数据库连接
* @throws Exception
*/
//这里不能用@After,当测试方法有@Rollback(false)注解时会在事务没有结束之前关闭了数据库连接
@AfterTransaction
public void teardown() throws Exception {
if (conn != null) {
conn.close();
}
}
/**
* Get Query DataSet
*
* @Title: getQueryDataSet
* @return
* @throws SQLException
*/
protected QueryDataSet getQueryDataSet() throws SQLException {
return new QueryDataSet(conn);
}
/**
* 备份表数据
*
* @Title: backupCustom
* @param tableName
* @throws Exception
*/
protected void backupCustom(String... tableName){
try {
// back up specific files
QueryDataSet qds = getQueryDataSet();
for (String str : tableName) {
qds.addTable(str);
}
tempFile = new File(ROOT_URL+"temp.xml");
FlatXmlDataSet.write(qds, new FileWriter(tempFile), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 清空表数据,并导入测试数据
* @throws Exception
*/
public void importTables(String file){
try {
IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File(ROOT_URL+file));
DatabaseOperation.CLEAN_INSERT.execute(conn, dataSet);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 回滚数据
*
* @Title: rollback
* @throws Exception
*/
protected void rollback(){
try {
// get the temp file
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
builder.setColumnSensing(true);
IDataSet ds =builder.build(new FileInputStream(tempFile));
// recover database
DatabaseOperation.CLEAN_INSERT.execute(conn, ds);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 清空表数据
*
* @param tableName
* @throws Exception
*/
protected void clearTable(String tableName){
try {
DefaultDataSet dataset = new DefaultDataSet();
dataset.addTable(new DefaultTable(tableName));
DatabaseOperation.DELETE_ALL.execute(conn, dataset);
}catch (Exception e) {
e.printStackTrace();
}
}
}
主要是准备查询数据用的service和dao,具体代码可以在https://gitee.com/oumuv/h2TestDemo下载
这里简单演示了两种方式实现数据库隔离测试,test1()方法用spring的事务特性,test2()使用DBunit手动回滚数据
/**
* 测试demo
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = H2Application.class)
public class TestDemo2 extends AbstractBaseTest{
@Autowired
DBunitService dBunitService;
/**
* 使用事务回滚机制,自动还原数据库
*/
@Test
public void test1() {
//导入测试数据
importTables("dbunit-data.xml");
List<DBunitEntity> list = dBunitService.list();
Assert.assertNotNull(list);
}
/**
* 加上注解 @Rollback(false) 不使用事务回滚,手动还原数据库
*/
@Test
@Rollback(false)
public void test2() {
//备份数据,备份数据在resources/temp.xml
backupCustom("db_unit_test");
//导入测试数据
importTables("dbunit-data.xml");
List<DBunitEntity> list = dBunitService.list();
Assert.assertNotNull(list);
//手动恢复数据
rollback();
}
}
运行测试用例发现查出来的数据确实是xml中的测试数据,而数据库中的数据并没有被污染也没有缺失,结果便是成功了!
具体代码可在https://gitee.com/oumuv/h2TestDemo自行下载