DbUnit(http://dbunit.sourceforge.net/ ) 是专门针对数据库测试的对JUnit 的一个扩展。本文介绍了使用 dbunit 工具让我们在测试的时候,不对数据库的数据造成破坏。本文介绍的思路其实很简单,对可能产生破坏的数据表进行备份(备份成一个 xml 文件),在测试通过以后,从之前备份的 xml 文件中将数据恢复。
使用 DbUnit 的步骤:
1、导入jar包
(1)dbunit.jar(可以从http://sourceforge.net/ 这个网站下载)
(2)slf4j.jar(可以从 Hibernate 的压缩包中找到)
2、创建 dbunit 的测试数据 xml 文件(注意路径)
说明:写下面配置文件的意义是,我们会根据下面这个配置文件生成或者保存数据库里面的一条记录,请留意:xml 文件里的一个子节点(以表名命名的),对应数据库表里的一条数据。
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<t_user id="1" username="admin" nickname="管理员" password="123456"></t_user>
</dataset>
说明:这里的 t_user 对应数据库的表名。
上面这种写法是比较常见的写法,我们也可以写成基于子节点的形式。
3、创建 dbunit 的Connection
dbunit 的 Connection 是用来对数据文件进行操作的,这个 Connection必须依赖于目前项目中所使用的 Connection。
IDatabaseConnection con = new DatabaseConnection(DbUtil.getConnection());
4、创建IDataSet,通过DataSet来获取测试数据中的数据(即 xml 文件里面的数据)
(1)FlatXmlDataSet 用来获取基于属性存储的属性值
(2)XMLDataSet 用来获取基于节点类型存储的属性值
下面的代码示例了 ,从自己写的一个 xml 文件中恢复数据的例子。
IDataSet ds =
new FlatXmlDataSet(new FlatXmlProducer(
new InputSource(
TestDbUnit.class.getClassLoader()
.getResourceAsStream(
"t_user.xml"))));
5、初始化数据并且完成测试
// 会将数据库中的数据清空,并且把测试数据插入
DatabaseOperation.CLEAN_INSERT.execute(con, ds);
// 从 DAO 中获取数据并且完成测试
IUserDao ud = new UserDao();
User tu = ud.load("admin");
assertEquals(tu.getId(), 1);
assertEquals(tu.getUsername(), "admin");
assertEquals(tu.getPassword(), "123");
assertEquals(tu.getNickname(), "超级管理员");
下面是一个完整的测试代码,但是这份代码的重用性还不太好,主要是让我们熟悉一下 dbunit 的常用 API。
package com.liwei.service;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.SQLException;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.AmbiguousTableNameException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Test;
import org.xml.sax.InputSource;
import com.liwei.dao.IUserDao;
import com.liwei.dao.UserDao;
import com.liwei.model.User;
import com.liwei.util.DBUtil;
/** * 10_junit_05dbunit的使用 这是一个 dbunit 的一个 HelloWolrd 练习 * 可以很清楚地发现:这个练习的代码拓展性很不好。每一次都要创建一个连接。 * * @author Administrator * */
public class TestDBunit {
@Test
public void testLoad() {
// 这里须要备份一下数据表
try {
// 创建一个 DBunit 的 Connection,须要传入一个 jdbc 的 Connection
IDatabaseConnection con = new DatabaseConnection(
DBUtil.getConnection());
/** * FlatXmlDataSet 用来获取基于属性存储的的属性值 XmlDataSet 用来获取基于节点类型存储的属性值 */
IDataSet ds = new FlatXmlDataSet(new FlatXmlProducer(
new InputSource(TestDBunit.class.getClassLoader()
.getResourceAsStream("dbunit_xml/t_user.xml"))));
// 会将数据库中的数据清空,并且把测试数据插入
DatabaseOperation.CLEAN_INSERT.execute(con, ds);
// 从 Dao 层中获取数据,并完成测试
IUserDao userDao = new UserDao();
User tu = userDao.load("admin");
assertEquals("用户 id 不匹配", tu.getId(), 1);
assertEquals("用户昵称不匹配", tu.getNickname(), "管理员");
assertEquals("用户登录名不匹配", tu.getUsername(), "admin");
assertEquals("用户密码不匹配", tu.getPassword(), "123456");
} catch (DatabaseUnitException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/** * 备份所有的数据表 */
@Test
public void testBackupAllTables() {
try {
// 创建一个 DBunit 的 Connection,须要传入一个 jdbc 的 Connection
IDatabaseConnection conn = new DatabaseConnection(
DBUtil.getConnection());
// 根据 conn 创建相应的 DataSet ,这个 DataSet 包含了所有的数据表
IDataSet ds = conn.createDataSet();
// 将 ds 中的数据通过 FlatXmlDataSet 这个格式写到 xml 文件中
FlatXmlDataSet.write(ds, new FileWriter(new File(
"d:\\tmp\\test.xml")));
} catch (DatabaseUnitException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/** * 备份部分的数据表 */
@Test
public void testBackTable() {
try {
IDatabaseConnection conn = new DatabaseConnection(
DBUtil.getConnection());
QueryDataSet backup = new QueryDataSet(conn);
// 添加 t_user 这张表作为备份的表
backup.addTable("t_user");
FlatXmlDataSet.write(backup, new FileWriter("d:\\tmp\\t_user.xml"));
} catch (AmbiguousTableNameException e) {
e.printStackTrace();
} catch (DatabaseUnitException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testResume() {
try {
// 创建 dbunit 的 Connnection ,需要传入一个数据库的 connection 作为参数
IDatabaseConnection conn = new DatabaseConnection(
DBUtil.getConnection());
// 根据备份文件创建 dataset
IDataSet ds = new FlatXmlDataSet(new FlatXmlProducer(
new InputSource(new FileInputStream("d:\\tmp\\test.xml"))));
DatabaseOperation.CLEAN_INSERT.execute(conn, ds);
} catch (DataSetException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DatabaseUnitException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
总结:上面的代码示例了备份数据库和恢复数据库的。
1、备份数据库的代码(从数据库备份数据库):
步骤:
(1)创建连接
(2)获取数据集(根据第1步创建的连接)
(3)通过 FlatXmlDataSet 写入到 xml 文件中
// 创建一个 DBunit 的 Connection,须要传入一个 jdbc 的 Connection
IDatabaseConnection conn = new DatabaseConnection(
DBUtil.getConnection());
// 根据 conn 创建相应的 DataSet ,这个 DataSet 包含了所有的数据表
IDataSet ds = conn.createDataSet();
// 将 ds 中的数据通过 FlatXmlDataSet 这个格式写到 xml 文件中
FlatXmlDataSet.write(ds, new FileWriter(new File(
"d:\\tmp\\test.xml")));
2、恢复数据库
步骤:
(1)创建连接 Conn;
(2)根据 xml 文件创建数据集 DataSet;
(3)根据连接和数据集,使用 DatabaseOperation 把测试好的数据库清空以后,插入之前备份的数据库。
// 创建 dbunit 的 Connnection ,需要传入一个数据库的 connection 作为参数
IDatabaseConnection conn = new DatabaseConnection(
DBUtil.getConnection());
// 根据备份文件创建 dataset
IDataSet ds = new FlatXmlDataSet(new FlatXmlProducer(
new InputSource(new FileInputStream("d:\\tmp\\test.xml"))));
DatabaseOperation.CLEAN_INSERT.execute(conn, ds);