1.DbUnit是junit的扩展,主要针对Dao层对数据库操作的单元测试,可以在不改变数据库原始数据的情况下,进行测试。
官网:http://dbunit.sourceforge.net/
下载地址:http://download.csdn.net/detail/sanfye/8992365
好了,废话不多说了,其它内容麻烦自己去科普,直接上代码:
2.直接继承 DatabaseTestCase 或 DBTestCase 进行测试,注意在项目中不建议这么做,因为它会把测试用例插入到数据库中并把真实数据给删除掉(可能是我的原因,有空了再研究),这只做入门测试使用。
//使用DBUnit进行数据库测试,可以继承自 DBTestCase或DatabaseTestCase(带数据库链接的)
public class UserDaoTest extends DatabaseTestCase{
private IUserDao userDao = new UserDao();
@Override
//处理数据链接的,如果是继承自DBTestCase则可以不用实现此方法,数据库的链接可以在构造函数中进行设置
protected IDatabaseConnection getConnection() throws Exception {
Class driverClass = Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/swh_hibernate4" ;
Connection jdbcConnect = DriverManager.getConnection(url,"root", "root");
IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnect);
//也可以直接指定数据库进行链接
// IDatabaseConnection databaseConnection = new MySqlConnection(jdbcConnect, "swh_hibernate4");
System.out.println("----->1. 进入 getConnection <----------");
return databaseConnection;
}
//
@Override
//从XML数据集中读取数据和结构,实例化为IDataSet对象,
//返回的Idataset代表数据表里面将要存放的数据。
//该方法会在getSetUpOperation和getTearDownOperation方法执行之后分别执行一次。
//注意:在getSetUpOperation之后执行 是 填充测试数据,在getTearDownOperation之后执行是为 恢复真实数据 (这两步操作需要自己控制)
protected IDataSet getDataSet() throws Exception {
System.out.println("----->3/5. 进入 getDataSet <----------");
//读取xml文件中的预存数据
InputStream is = new FileInputStream("src/test/resources/com/swh/user/dao/t_user.xml");
Assert.assertNotNull("dbunit的基本数据文件不存在",is);
//从2.4.7之后DBUnit就不推荐使用FlatXmlDataSet()方法了 。
// IDataSet dataSet = new FlatXmlDataSet(is);
IDataSet dataSet = new FlatXmlDataSetBuilder().build(is);
return dataSet;
}
@Override
//可选的覆盖,该方法代表运行该测试用例之前,要作的操作。默认就是CLEAN_INSERT
//通过覆盖DatabaseTestCase中的getSetUpOperation()方法来实现自己的动作
protected DatabaseOperation getSetUpOperation() throws Exception {
System.out.println("----->2. 进入 getSetUpOperation <----------");
//先清空数据表里的数据,再插入 getDataSet 返回的数据到数据表中,
// DatabaseOperation.INSERT :是默认操作(也是我们常用的操作) (它首先会将目标数据库中与我们提供的种子文件一致的数据删除,然后将我们提供的数据插入到数据库中。这个实施顺序保证了我们对数据库的精确控制 ) 。
//DatabaseOperation.NONE: 不做任何事情。
//DatabaseOperation.REFRESH:通过这个操作,我们可以用种子文件中的数据去更新目标数据库里的数据
//还有 DatabaseOperation.UPDATE 、 DatabaseOperation.DELETE 、 DatabaseOperation.DELETE_ALL 、 DatabaseOperation.TRUNCATE 、 CompositeOperation 、 TransactionOperation 和 IdentityInsertOperation 等几个状态
return DatabaseOperation.CLEAN_INSERT ;
};
@Override
// 可选的覆盖,该方法代表运行完该测试,要做的操作。默认就是NONE
protected DatabaseOperation getTearDownOperation() throws Exception {
System.out.println("----->4. 进入 getTearDownOperation <----------");
return DatabaseOperation.NONE;
}
@Test
public void testAdd(){
System.out.println("----->进入 testAdd <----------");
User user = new User();
user.setUsername("testAdd");
user.setPassword("456");
user.setNickname("测试4");
userDao.add(user);
User user_ = userDao.loadByUserName(user.getUsername());
assertEquals("testAdd",user_.getUsername());
}
@Test
public void testLoadByUserName(){
System.out.println("----->进入 testLoadByUserName <----------");
User user = userDao.loadByUserName("test2");
assertEquals("测试员2", user.getNickname());
}
}
执行后数据库中的记录:
3.封装自己的DBUnit测试类或抽象测试类(使用dbunit中提供的方法),主要思路是 备份数据库中真实数据-->清除真实数据并插入测试用例数据-->执行测试用例-->清除测试数据并恢复真实数据;另外,该类也可以继承 DatabaseTestCase 或 DBTestCase 实现其中的方法按照上面的思路进行封装。
/**
* DBUnit Dao数据库 测试 的抽象类,
* Dao层方法的测试只需继承此类,
* 并调用相应的方法即可完成隔离真实数据层的数据测试
* @author
* 2015.08.11
*
*/
public abstract class AbstractDbUnitTestCase {
//数据库链接
public static IDatabaseConnection dbunitCon ;
//备份真实数据的文件
private File tempFile ;
@BeforeClass
//在类执行之前执行,初始化数据库链接
public static void init() throws DatabaseUnitException{
dbunitCon = new DatabaseConnection(DbUtil.getConnection());
}
/**
* 构建初始 测试 数据集
* @param tname 要构建的数据集的数据文件名 tname.xml
* @return
* @throws DataSetException
*/
protected IDataSet createDataSet(String tname) {
//获取预置数据集
InputStream is = AbstractDbUnitTestCase.class.getResourceAsStream("/com/swh/user/dao/"+tname+".xml");
Assert.assertNotNull("dbunit的基本文件 "+tname+".xml 不存在",is);
//构建数据集
IDataSet dataSet = null;
try {
dataSet = new FlatXmlDataSetBuilder().build(is);
} catch (DataSetException e) {
e.printStackTrace();
}
return dataSet ;
}
//===========备份真实数据的公共方法==========================================================//
/**
* 备份数据表
* @param tname
* @throws DataSetException
* @throws IOException
*/
protected void backUpOneTable(String tname) {
backUpCustomTable(new String[]{tname});
}
/**
* 同时备份多张表
* @param tname
* @throws DataSetException
* @throws IOException
*/
protected void backUpCustomTable(String[] tname) {
try {
QueryDataSet queryDataSet = new QueryDataSet(dbunitCon);
for(String str : tname){
queryDataSet.addTable(str);
}
writeBackUpFile(queryDataSet);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 备份全部的真实数据表
* @author sangwenhao
* 2015.08.10
*/
protected void backUpAllTable(){
try {
IDataSet dataSet = dbunitCon.createDataSet();
//保存到物理文件
writeBackUpFile(dataSet);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 保存临时文件(数据库中真实数据)操作
* @param dataSet
* @author sangwenhao
* 2015.08.11
*/
protected void writeBackUpFile(IDataSet dataSet) {
try {
tempFile = File.createTempFile("back", "xml");
FlatXmlDataSet.write(dataSet, new FileWriter(tempFile) );
} catch (IOException e) {
e.printStackTrace();
} catch (DataSetException e) {
e.printStackTrace();
}
}
/**
* 恢复数据表中的原始数据
* @author sangwenhao
* 2015.08.10
*/
protected void resumeTable() {
try {
//读取 备份的真实数据集
IDataSet ds = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(new FileInputStream(tempFile))));
//执行 插入数据 操作
DatabaseOperation.CLEAN_INSERT.execute(dbunitCon, ds);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 销毁链接
* @author sangwenhao
* 2015.08.10
*/
protected void destory() {
try {
if(dbunitCon != null) dbunitCon.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试用例的实现方法(注意:测试方法是倒着执行的):
//使用DBUnit进行数据库测试,可以继承自 DBTestCase或DatabaseTestCase(带数据库链接的)
public class UserDaoTest extends DatabaseTestCase{
private IUserDao userDao = new UserDao();
@Override
//处理数据链接的,如果是继承自DBTestCase则可以不用实现此方法,数据库的链接可以在构造函数中进行设置
protected IDatabaseConnection getConnection() throws Exception {
Class driverClass = Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/swh_hibernate4" ;
Connection jdbcConnect = DriverManager.getConnection(url,"root", "root");
IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnect);
//也可以直接指定数据库进行链接
// IDatabaseConnection databaseConnection = new MySqlConnection(jdbcConnect, "swh_hibernate4");
System.out.println("----->1. 进入 getConnection <----------");
return databaseConnection;
}
//
@Override
//从XML数据集中读取数据和结构,实例化为IDataSet对象,
//返回的Idataset代表数据表里面将要存放的数据。
//该方法会在getSetUpOperation和getTearDownOperation方法执行之后分别执行一次。
//注意:在getSetUpOperation之后执行 是 填充测试数据,在getTearDownOperation之后执行是为 恢复真实数据 (这两步操作需要自己控制)
protected IDataSet getDataSet() throws Exception {
System.out.println("----->3/5. 进入 getDataSet <----------");
//读取xml文件中的预存数据
InputStream is = new FileInputStream("src/test/resources/com/swh/user/dao/t_user.xml");
Assert.assertNotNull("dbunit的基本数据文件不存在",is);
//从2.4.7之后DBUnit就不推荐使用FlatXmlDataSet()方法了 。
// IDataSet dataSet = new FlatXmlDataSet(is);
IDataSet dataSet = new FlatXmlDataSetBuilder().build(is);
return dataSet;
}
@Override
//可选的覆盖,该方法代表运行该测试用例之前,要作的操作。默认就是CLEAN_INSERT
//通过覆盖DatabaseTestCase中的getSetUpOperation()方法来实现自己的动作
protected DatabaseOperation getSetUpOperation() throws Exception {
System.out.println("----->2. 进入 getSetUpOperation <----------");
//先清空数据表里的数据,再插入 getDataSet 返回的数据到数据表中,
// DatabaseOperation.INSERT :是默认操作(也是我们常用的操作) (它首先会将目标数据库中与我们提供的种子文件一致的数据删除,然后将我们提供的数据插入到数据库中。这个实施顺序保证了我们对数据库的精确控制 ) 。
//DatabaseOperation.NONE: 不做任何事情。
//DatabaseOperation.REFRESH:通过这个操作,我们可以用种子文件中的数据去更新目标数据库里的数据
//还有 DatabaseOperation.UPDATE 、 DatabaseOperation.DELETE 、 DatabaseOperation.DELETE_ALL 、 DatabaseOperation.TRUNCATE 、 CompositeOperation 、 TransactionOperation 和 IdentityInsertOperation 等几个状态
return DatabaseOperation.CLEAN_INSERT ;
};
@Override
// 可选的覆盖,该方法代表运行完该测试,要做的操作。默认就是NONE
protected DatabaseOperation getTearDownOperation() throws Exception {
System.out.println("----->4. 进入 getTearDownOperation <----------");
return DatabaseOperation.NONE;
}
@Test
public void testAdd(){
System.out.println("----->进入 testAdd <----------");
User user = new User();
user.setUsername("testAdd");
user.setPassword("456");
user.setNickname("测试4");
userDao.add(user);
User user_ = userDao.loadByUserName(user.getUsername());
assertEquals("testAdd",user_.getUsername());
}
@Test
public void testLoadByUserName(){
System.out.println("----->进入 testLoadByUserName <----------");
User user = userDao.loadByUserName("test2");
assertEquals("测试员2", user.getNickname());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- 使用DBUnit进行测试的 测试数据 -->
<dataset>
<!-- 标签名应和数据库中表的名称对应;下面标签与数据库中表名:user对应
属性名应和数据库中表的字段名称对应。
-->
<t_user id="1" username="admin" password="123456" nickname="管理员" />
<t_user id="2" username="test2" password="123456" nickname="测试员2" />
<t_user id="3" username="test3" password="123" nickname="测试员3" />
</dataset>
不喜勿喷,有不对的地方请指出,以便及时更正。