没有比人更高的山

DbUnit中文教程——核心组件0

注:本文基本翻译自DbUnit的文档,翻译不好朋友见谅

本文主要介绍在使用DBUnit编写测试用例的时候会常用的几个接口和类
IDatabaseConnection:接口,DbUnit的数据库连接对象,封装了java.sql.Connection
IDataSet:接口,DbUnit的数据集对象,里面可以放多个数据表
DataBaseOperation:抽象类,数据库操作类
 
IDatabaseConnection有两个子类:
DatabaseConnection:封装了一个普通的JDBC连接
DatabaseDataSourceConnection:封装了一个JDBC数据源连接
 
IDataSet是DbUnit用来存储数据的一种数据结构
FlatXmlDataSet:最普遍使用的数据集,每个XML元素代表数据表中的一行数据,XML元素的名称是表明,属性名是列名
XmlDataSet
StreamingDataSet
DatabaseDataSet
QueryDataSet
DefaultDataSet
CompositeDateSet
FilteredDataSet
XlsDataSet
ReplacementDataSet
 
DatabaseOperation
DatabaseOperation.UPDATE:这个操作将从测试数据源中读取的数据集的内容更新到数据库中,注意这个操作正确执行的前提是测试数据表已经存在,如果不存在这个测试用例将会失败
DatabaseOperation.INSERT:这个操作把从测试数据源中读取的数据集的内容插入到数据库中,注意这个操作正确执行的前提是测试数据表不存在,这个操作将新建数据表。如果测试数据表已经存在这个测试用例将会失败。另外,在执行这个操作的时候要特别注意数据集中数据表的顺序,否则可能会因为违反外键约束而造成测试用例失败
DatabaseOperation.DELETE:这个操作会从数据库中删除数据,注意,这个操作只删除数据集中存在的数据行而不是整个数据表中的数据
DatabaseOperation.DELETE_ALL:这个操作删除数据表中的所有行,注意,这个操作也只影响数据集中声明了的数据表,数据集中没有涉及到的数据表中的数据不会删除
DatabaseOperation.TRUNCATE:这个操作将删除数据集中声明的数据表,如果数据中有些表并没有在预定义的数据集中提到,这个数据表将不会被影响。注意,这个操作是按照相反的顺序执行的
DatabaseOperation.REFRESH:顾名思义,这个操作将把预定义数据集中的数据同步到数据库中,也就是说这个操作将更新数据数中已有的数据、插入数据库中没有的数据。数据库中已有的、但是数据集中没有的行将不会被影响。我们用一个产品数据库的拷贝进行测试的时候可以使用这个操作将预定义数据同步到产品数据库中
DatabaseOperation.CLEAN_INSERT:删除所有的数据表中的数据,然后插入数据集中定义的数据,如果你想保证数据库是受控的,这个你会比较喜欢。
DatabaseOperation.NONE:不执行任何操作
CompositeOperation:将多个操作组合成一个,便以维护和重用
TransactionOperation:在一个事物内执行多个操作
IdentityInsertOperation:在使用MSSQL的时候,插入数据时IDENTITY列我们是没有办法控制的,用这个就可以控制了,只有在使用MSSQL的时候才会用得到
VN:F [1.7.5_995]
Rating: 10.0/10 (1 vote cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

DbUnit中文教程——基本原理和简单开始0

DBUnit是JUnit的一个扩展,对于数据库驱动的项目而言(基本上所有的Web项目都是数据库驱动的),对于服务层的单元测试非常麻烦,因为不能保证每次测试时数据库都是同一个状态,所以开发者不敢写断言(assertEquals())。我个人也是因为这个原因所以对驱动测试开发总是敬而远之。

有了DBUnit,一切都变了,DBUnit的目的就是在每个单元测试运行之前将数据库初始化成一个预定义的状态,以保证单元测试时的断言不会因为数据库状态发生了变化而失败,同时可以解决前一个单元测试失败导致对数据库的操作未按照测试用例执行而影响后一个单元测试的问题。

DBUnit可以将数据库中的数据导出成XML数据集,也可以将XML数据集重新导入到数据库中,这也是DBUnit实现测试前初始化数据库状态的实现方法,而且,DBUnit还可以验证数据库中的模式和数据是不是和XML数据集中的模式和数据是否一样,也就是真正意义上的“数据库测试”,不过DBUnit貌似还不支持数据库存储过程、触发器、视图等高级功能的测试。DBUnit2.0增强了对于流模式下巨型XML数据集的支持。

相信信仰单元测试驱动开发或者有意向在开发中加入单元测试的开发者很容易理解上面的叙述,下面用一个示例演示DBUnit的功能。

假设我们开发中已经建立了一个数据库,里面只有一个数据表user:

create table user
(
id bigint auto_increament primary key,
username char(48) not null,
password char(48) not null,
name varchar(48) not null
);

其中有一行数据:
insert into user(id, username, password, name) values(1, 'admin', '123', 'Administrator');

第一步是根据测试数据建立XML数据集,DBUnit用下面的格式来表示一行数据:
<user id="1" username="admin" password="123" name="Administrator" />

一个XML数据集应该具有如下格式:

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <user id="1" username="admin1" password="123" name="Administrator1" />
    <user id="2" username="admin2" password="123" name="Administrator2" />
    <user id="3" username="admin3" password="123" name="Administrator3" />
</dataset>

 

一般,最好对每个需要数据库驱动的测试用例都建立一个XML数据集,一方面可以保证单元测试之间完全的数据独立,另一方面可以只设置测试需要的数据,尽量使XML数据集保持简单可控。

第二步就可以开始编码了,DBUnit提供了一个抽象类DatabaseTestCase,这个类继承了JUnit的TestCase类,其中定义了两个抽象方法: 
/**
 * 返回测试用的数据库连接对象
 */
protected abstract IDatabaseConnection getConnection() throws Exception;

/**
 * 返回测试用XML数据集对象
 */
protected abstract IDataSet getDataSet() throws Exception; 

getConnection()的返回值类型为IDatabaseConnection,对java.sql.Connection进行了简单的封装,可以简单的实现如下:
 protected IDatabaseConnection getConnection() throws Exception {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/dbunitdemo", "root", "admin");
    return new MySqlConnection(conn, "dbunitdemo");//本人用的是MySQL
}

getDataSet()的返回值是IDataSet类型,即从XML数据集中读取数据和结构,实例化为IDataSet对象,可以简单实现如下:
protected IDataSet getDataSet() throws Exception {
    InputStream is = new FileInputStream("dbunitdemo-seed.xml");
    return new FlatXmlDataSet(is);
}

定义了以上两个方法后,DBUnit就可以工作了,但是不少人会就会想到一个问题,如果数据库中存在以前的数据,而我需要将这些数据删除,DBUnit会自动的帮我做这些事情么?事实上,很显然DBUnit会,其默认操作就是删除数据,同时将XML数据集中的数据插入到数据库中,不过DBUnit也允许我们通过覆盖DatabaseTestCase中的getSetUpOperation()方法来实现自己的动作,在DatabaseTestCase中默认实现是这样的:
protected DatabaseOperation getSetUpOperation() throws Exception
{
    return DatabaseOperation.CLEAN_INSERT;
}

DatabaseOperation是DBUnit定义的数据库操作对象,CLEAN_INSERT代表清空数据、插入XML数据集数据的操作。 

与SetUpOperation对象就有TearDownOperation,表示结束测试的时候做的事情,DatabaseTestCase的默认实现是什么都不做:
protected DatabaseOperation getTearDownOperation() throws Exception
{
    return DatabaseOperation.NONE;
}
同样,开发者可以根据自己的需求来改变默认操作。

基本原理就已经讲解完了,我写了一个例子程序,实现了一个领域模型类(User),一个Dao接口(IUserDao),定义了list\save\get\delete四个基本方法,一个用JDBC实现的Dao接口实现类(UserDaoImpl),建立一个UserDaoTest对JBDC版本的Dao实现类进行测试。

例子程序下载地址:dbunitdemo_jdbc_1.0.zip

另外这个工程使用maven进行build,如果你对maven还是不很了解,请查考《Maven权威指南》

下载工程后,在项目根目录下执行mvn sql:execute,将使用Maven Sql插件导入src/main/sql/dbunitdemo.sql中的数据库脚本到数据库中。

然后可以直接运行mvn test进行单元测试,测试报告会在命令行输出,同时在target\surefire-reports下也会生成DBUnit报告

VN:F [1.7.5_995]
Rating: 3.3/10 (3 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 2 votes)