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>