日期:2014-05-16  浏览次数:20734 次

用DbUnit进行数据库集成测试
http://www.cnblogs.com/kirinboy/archive/2012/06/06/integration-testing-with-dbunit.html
现在的DbUnit要求在测试时继承DBTestCase,而不是之前的DatabaseTestCase(前者继承自后者,而后者继承了junit的TestCase)。DatabaseTestCase包含两个抽象方法,getConnection()和getDataSet(),前者用来获取数据库连接,后者获取要测试的数据集。

数据集
DbUnit可以把所有表的记录存在一个数据集中:既可以是数据库中的表,也可以是文件中的数据。我们在此用FlatXmlDataSet来演示。
顺便提一句,DbUnit中还存在另一种格式的数据集XmlDataSet,它们的区别如下:
在FaltXmlDataSet对应的XML文件里,元素名称对应数据库表名,元素的属性(attribute)对应表的列。如:
<dataset>
    <Person Name="Kirin" Age="31" Location="Beijing"/>
    <Person Name="Jade" Age="30"/>
</dataset>

要注意,如果数据库中某一条字段为null,在flat XML中将不会显示该attribute。另外,FlatXmlDataSet用XML文件中该表的第一行数据来制定表的结构。因此,如果数据库中某个字段所有记录都为null,或者恰巧第一条记录为null,那么得到的表结构与原数据库的表结构就不一致了,测试就会失败。FlatXmlDataSet中存在一个column sensing的概念,在从文件加载数据时,将该属性设置为true,就会根据第一行展现出来的表结构,自动将别的行的列补齐。
在XmlDataSet对应的XML文件里,用元素的子元素对应表的列。如:
<dataset>
    <Person>
        <Name>Kirin</Name>
        <Age>31</Age>
        <Location>Beijing</Location>
    </Person>
    <Person>
        <Name>Jade</Name>
        <Age>30</Age>
        <Location/>
    </Person>
</dataset>

null用空元素来表示。
将数据库导出到XML文件
我们可以手写XML来准备数据,也可以从数据库中导出现有的数据,用FlatXmlDataSet.write()静态方法即可,例如:
QueryDataSet dataSet = new QueryDataSet(connection);
dataSet.addTable(TABLE_NAME, "select * from " + TABLE_NAME);
dataSet.addTable(...);
FlatXmlDataSet.write(dataSet, new FileOutputStream("data.xml"));

重写getDataSet
有了文件数据,我们就需要重写getDataSet(),让它加载文件中的数据并返回。
@Override
protected IDataSet getDataSet() throws Exception {
    // set column sensing as true, so it can dynamically and columns with null value. 
    return new FlatXmlDataSetBuilder()                  
                .setColumnSensing(true)
                .build(new FileInputStream("data.xml"));
}


IDatabaseTester
DBTestCase重写了getConnection(),并把它设置为final,将获取connection的操作委托给IDatabaseTester,我们可以通过重写getDatabaseTester()方法来设置具体的IDatabaseTester。Dbunit中,IDatabaseTester的实现类一共有四个:
DefaultDatabaseTester
JdbcDatabaseTester
DataSourceDatabaseTester
JndiDatabaseTester

它们的用途不言自明。
DatabaseTestCase重写了TestCase里的setUp()和tearDown()方法。
protected void setUp() throws Exception
{
    super.setUp();
    final IDatabaseTester databaseTester = getDatabaseTester();
    assertNotNull( "DatabaseTester is not set", databaseTester );
    databaseTester.setSetUpOperation( getSetUpOperation() );
    databaseTester.setDataSet( getDataSet() );
    databaseTester.setOperationListener(getOperationListener());
    databaseTester.onSetup();
}

protected void tearDown() throws Exception
{
    try {
        final IDatabaseTester databaseTester = getDatabaseTester();
        assertNotNull( "DatabaseTester is not set", databaseTester );
        databaseTester.setTearDownOperation( getTearDownOperation() );
        databaseTester.setDataSet( getDataSet() );
        databaseTester.setOperationListener(getOperationListener());
        databaseTester.onTearDown();
    } finally {
        tester = null;
        super.tearDown();
    }
}

可以看出它们的大体意图:为tester设置操作、数据集和监听器,然后执行相应的操作。获取数据集的是抽象方法,需要我们来实现。监听器主要负责在得到数据连接或setUp、tearDown结束后执行的操作,使用默认实现即可。我们主要来说说getSetUpOperation和getTearDownOperation返回的DatabaseOperation。

DatabaseOperation
DatabaseOperation定义了对数据库进行的操作,它是一个抽象类,通过静态字段提供了几种内置的实现:
NONE:不执行任何操作,是getTearDownOperat