本文主要为对dbunit getting started 简单理解,其他参考文章见文末。
1. 为什么要用DbUnit
dbunit(官网:http://www.dbunit.org/)是一种扩展于JUnit的数据库驱动测试框架,它使数据库在测试过程之间处于一种已知状态,如果一个测试用例对数据库造成了破坏性影响,它可以帮助避免造成后面的测试失败或者给出错误结果。这是官方的解释,个人理解dbunit的好处是如果一个测试用例影响了数据库,或者说数据库被发生了变动,dbunit可以很容易地发现问题,并使其他测试用例不受影响,也就是一种已知并可控的状态。
dbunit属于极限编程(Extreme Programming)范畴,推荐测试优先的开发和持续集成。个人觉得dbunit最大的好处就在这“持续集成”上。以前只要数据库发生变化,比如改了表结构,哪怕仅仅添加一个字段,后续工作也不少,已经写完的相关DAO必须得改,测试用例也要改,改了数据库忘记改代码的情况也不少见。这还是对一个人来说,如果是多人合作,你很大可能会碰到这种情况:boss指着屏幕质问你:为什么10分钟前测试通过的功能,现在连界面都看不到...于是你装无辜,装可怜,查日志,查代码,最后只能无力地怒吼:谁动了我的数据.....很多时候单元测试只不过是一种摆设,少有项目完成后还可以完整运行的测试方法,如果你能迅速地跑起测试用例,问题自然暴露,让我们来看看dbunit如何来解决这些问题。
2.DbUnit原理
dbunit通过维护真实数据库与数据集(DataSet)之间的关系来发现与暴露测试过程中的问题。此处DataSet可以自建,可以由数据库导出,并以多种方式体现,xml文件、XLS文件和数据库查询数据等,一般多用XML文件。在测试过程中,DataSet被称为期望结果(expected result),真实数据库被称真实结果(actual result),你所要做的就是通过dbunit完成期望结果与真实结果之间的操作与比较,从而发现问题和校验结果。
dbUnit包括三个核心部分(详见:http://www.dbunit.org/components.html#cleanInsert):
1)IDatabaseConnection :描述dbunit数据库连接接口;
2)IDataSet:数据集操作接口;
3)DatabaseOperation:描述测试用例测试方法执行前与执行后所做操作的抽象类;
值得关注的是 DatabaseOperation的各种实现,比较常用的有 REFRESH、DELETE_ALL和CLEAN_INSERT等。这些操作关系到数据集与数据库数据的同步、数据准备,不小心就会对数据库原有数据造成影响,所以务必做好备份。
DatabaseOperation.REFRESH:同步DataSet数据到目标数据库,DataSet中有database中也有的数据,会从DataSet更新到database,DataSet中有database中没有的数据会插入到database中。对database中有DataSet中没有的数据不造成影响,适用于database中有其他数据的情况;
DatabaseOperation.DELETE_ALL:删除database中DataSet有的所有表数据,DataSet中没有的表不造成影响。
DatabaseOperation.CLEAN_INSERT:先进行DELETE_ALL操作,在把DataSet中有database中没有的数据插入database;
3.DbUnit应用流程
1) 准备DataSet;
即准备测试数据(expected result),可以手写,也可以直接从数据库中导出,以XML文件为列,导出代码如下:
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost/ecshop", "root", "");
IDatabaseConnection connection = new DatabaseConnection(conn);
QueryDataSet dataSet = new QueryDataSet(connection);
//将整个ecs_card表里的数据导出到 xml文件里
dataSet.addTable("ecs_card");
FlatXmlDataSet.write(dataSet, new FileOutputStream("ecs_card.xml"));
//导出数据库所有表
//IDataSet dataSet= connection.createDataSet();
// FlatXmlDataSet.write(dataSet, new FileOutputStream("allTable.xml"));
}
2)继承dbunit的测试基类DBTestCase ,建立数据库与数据集的连接;
dbunit封装了四种数据库连接配置方式:PropertiesBasedJdbcDatabaseTester、JdbcBasedDBTestCase、JndiBasedDBTestCase和DataSourceBasedDBTestCase,默认使用PropertiesBasedJdbcDatabaseTester。最好在你的测试类构造方法中配置。DataSet加载以重载基类
getDataSet()方法实现,代码如下:
public class SimpleTest extends DBTestCase
{
public SimpleTest(String name)
{
super( name );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "com.mysql.jdbc.Driver" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:mysql://localhost/ecshop?useUnicode=true&characterEncoding=GBK" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, "root" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, "" );
// System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_SCHEMA, "" );
}
@Override
protected IDataSet getDataSet() throws Exception
{
return new FlatXmlDataSetBuilder().build(new FileInputStream("ecs_card.xml"));
}
}
3) (可选) 实现基类 getSetUpOperation() and getTearDownOperation() 方法;
public class SimpleTest extends DBTestCase
{
...
@Override
protected DatabaseOperation getSetUpOperation() throws Exception {
logger.info("setup REFRESH operation....");
return DatabaseOperation.REFRESH; //刷新dataset 数据到 database
// return DatabaseOperation.REFRESH; //
}
@Override
protected DatabaseOperation getTearDownOperation() throws Exception {
logger.info("teardown NONE operation....");
return DatabaseOperation.NONE; //do nothing
}
...
}
4) 编写测试方法testXXX(),完整测试用例如下:
public class SimpleTest extends DBTestCase{
private static Log logger = LogFactory.getLog(SimpleTest.class);
public SimpleTest() {
}
public SimpleTest(String name) {
super(name);
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "com.mysql.jdbc.Driver" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:mysql://localhost/ecshop?useUnicode=true&characterEncoding=GBK" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, "root" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, "" );
// System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_SCHEMA, "" );
}
@Override
protected IDataSet getDataSet() throws Exception {
logger.info("load xml data....");
return new FlatXmlDataSetBuilder().build(new FileInputStream("ecs_card.xml")); //To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected DatabaseOperation getSetUpOperation() throws Exception {
logger.info("setup clean_insert operation....");
return DatabaseOperation.REFRESH; //
// return DatabaseOperation.REFRESH; //
}
@Override
protected DatabaseOperation getTearDownOperation() throws Exception {
logger.info("teardown NONE operation....");
return DatabaseOperation.NONE; //do nothing
}
/**
* 数据库与备份库比较
* @throws Exception
*/
public void testdb() throws Exception{
//取数据库表
IDataSet dataSet = getConnection().createDataSet();
ITable dbTable = dataSet.getTable("ecs_card");
//取XML备份表
ITable xmlTable = getXmlTable("ecs_card","ecs_card");
Assertion.assertEquals(xmlTable,dbTable);
}
/**
* 测试表结构
* @throws Exception
*/
public void testDbStructure() throws Exception {
//取数据库表
IDataSet dataSet = getConnection().createDataSet();
ITable dbTable = dataSet.getTable("ecs_card");
//取XML备份表
ITable xmlTable = getXmlTable("ecs_card1","ecs_card");
dbTable = DefaultColumnFilter.includedColumnsTable(dbTable,xmlTable.getTableMetaData().getColumns());
Assertion.assertEquals(xmlTable,dbTable);
}
/**
* 测试插入一条记录
* @throws Exception
*/
public void testInsertRecord() throws Exception {
/*这里dao 插入一条记录,省略*/
IDataSet dataSet = getConnection().createDataSet();
ITable dbTable = dataSet.getTable("ecs_card");
//取XML期望表
ITable xmlTable = getXmlTable("ecs_card_exp","ecs_card");
Assertion.assertEquals(xmlTable,dbTable);
}
public void testQueryRecord() throws Exception {
/*这里dao 查询,省略*/
String sql = "SELECT *FROM ecs_card ";
ITable dbTable = (ITable) getConnection().createQueryTable("ecs_card",sql);
assertEquals(1,dbTable.getRowCount());
String cardName = (String) dbTable.getValue(0,"card_name");
assertEquals("贺卡",cardName);
}
/**
* 获取XML TABLE,默认取当前目录
* @param xmlFileName
* @param tableName
* @return
* @throws Exception
*/
private ITable getXmlTable(String xmlFileName,String tableName) throws Exception {
//取XML备份表
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
builder.setColumnSensing(true);
IDataSet xmlDataSet = builder.build(new FileInputStream(xmlFileName+".xml"));
return xmlDataSet.getTable(tableName);
}
}
4. 依赖包
5. 参考文章
分享到:
相关推荐
### DBUnit简介 DBUnit是一个强大的工具,它允许开发者在测试用例之间对数据库进行"干净"的状态设置。这通常涉及到在每个测试之前清除数据,然后插入特定的测试数据。DBUnit通过使用XML或Flat CSV格式的数据集来...
一、DBUnit 简介 DBUnit 提供了一套接口和类,使得测试用例可以方便地导入和导出数据库中的数据。它支持多种数据格式,如CSV、XML和Excel,使得测试数据的准备和清理变得更加便捷。DBUnit 可以帮助我们创建一致的...
**一、DbUnit简介** DbUnit是一个用于数据库集成测试的Java工具,它允许开发者通过导入和导出结构化数据(通常以CSV或XML格式)来控制测试环境中的数据库状态。这有助于确保测试的隔离性和准确性,因为每次测试前后...
1. Hibernate简介 Hibernate是一个强大的ORM框架,允许开发者使用面向对象的方式来操作数据库。它通过映射Java对象到数据库表,使得数据操作变得直观且高效。Hibernate支持多种关系映射,如继承、关联(一对一、一...
【个人简介】 XXX,来自四川省,毕业于xx大学,拥有丰富的Java开发经验,专长在于JavaSE和JavaEE领域,具备面向对象的编程思维。在实际工作中,我曾参与多个项目,涵盖单车租赁、核电站环境监测、手机进销存管理和...
Unitils构建在DBUnit与EasyMock项目之上并与JUnit和TestNG相结合,支持数据库测试,支持利用mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散偶合的框架来添加这些服务到单元...
### Hibernate简介 Hibernate是一种开源的对象关系映射(ORM)框架,用于Java应用程序与数据库之间的交互。它为开发人员提供了一种将Java对象映射到数据库表,并将SQL查询语句转换为面向对象API的方法。这使得...
### Hibernate简介 Hibernate作为ORM框架,其核心功能是将Java对象映射到关系型数据库的表中,并将Java类的操作转换为SQL语句执行。这种映射机制不仅提高了代码的可读性和可维护性,还极大地减少了数据库操作的...
JUnit简介 - **定义**:JUnit是一个广泛使用的Java单元测试框架,旨在简化测试过程并提高软件质量。 - **版本更新**:本书重点介绍了JUnit 4.8版本,该版本对Java开发流程进行了显著优化,包括对新应用程序类型的...
接口测试的技术简介 本节将简要介绍几种常用的接口测试技术和工具,包括: ##### 5.1 Junit Junit 是 Java 平台上的一个单元测试框架,广泛用于接口测试。它支持编写和运行自动化的测试案例,帮助开发者快速发现...
#### 一、书籍简介与价值 《JUnit in Action, 2nd Edition》是一本深入介绍JUnit框架的专业书籍,适用于希望提高单元测试技能和软件质量意识的程序员。本书由Tahchiev、Leme、Massol 和 Gregory 合著,于2009年出版...
- **扩展性**:能够与第三方工具或框架(如Mockito、Dbunit等)良好配合,以支持模拟对象、断言和数据库操作等功能。 ##### 2. 测试框架的对比 - **JUnit**: JUnit是最早也是最广泛使用的Java单元测试框架之一,...