`
gavin213
  • 浏览: 34193 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论
阅读更多

   本文主要为对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. 依赖包

      dbunit所有依赖包见:http://www.dbunit.org/dependencies.html,可直接下载。 简单功能当然不用全部,包含junit、slf4j和commons几个包就可以了。
 5. 参考文章
     dbunit getting started:http://www.dbunit.org/howto.html;
1
2
分享到:
评论
1 楼 u014701409 2014-11-25  
非常感谢 ,照着文档入门,修改几个地方后,可以跑了,谢谢

相关推荐

    dbunit帮助文档(HTML版)

    ### DBUnit简介 DBUnit是一个强大的工具,它允许开发者在测试用例之间对数据库进行"干净"的状态设置。这通常涉及到在每个测试之前清除数据,然后插入特定的测试数据。DBUnit通过使用XML或Flat CSV格式的数据集来...

    DBUnit最佳实践之使用ant命令

    一、DBUnit 简介 DBUnit 提供了一套接口和类,使得测试用例可以方便地导入和导出数据库中的数据。它支持多种数据格式,如CSV、XML和Excel,使得测试数据的准备和清理变得更加便捷。DBUnit 可以帮助我们创建一致的...

    dbunit-2.4.7

    **一、DbUnit简介** DbUnit是一个用于数据库集成测试的Java工具,它允许开发者通过导入和导出结构化数据(通常以CSV或XML格式)来控制测试环境中的数据库状态。这有助于确保测试的隔离性和准确性,因为每次测试前后...

    用 hibernate 和 spring 开发持久层.doc

    1. Hibernate简介 Hibernate是一个强大的ORM框架,允许开发者使用面向对象的方式来操作数据库。它通过映射Java对象到数据库表,使得数据操作变得直观且高效。Hibernate支持多种关系映射,如继承、关联(一对一、一...

    JavaEE求职简历-姓名-JAVA开发工程师.doc

    【个人简介】 XXX,来自四川省,毕业于xx大学,拥有丰富的Java开发经验,专长在于JavaSE和JavaEE领域,具备面向对象的编程思维。在实际工作中,我曾参与多个项目,涵盖单车租赁、核电站环境监测、手机进销存管理和...

    Unitils框架与模块扩展

    Unitils构建在DBUnit与EasyMock项目之上并与JUnit和TestNG相结合,支持数据库测试,支持利用mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散偶合的框架来添加这些服务到单元...

    Hibernate Quickly

    ### Hibernate简介 Hibernate是一种开源的对象关系映射(ORM)框架,用于Java应用程序与数据库之间的交互。它为开发人员提供了一种将Java对象映射到数据库表,并将SQL查询语句转换为面向对象API的方法。这使得...

    Manning_Hibernate.Quickly

    ### Hibernate简介 Hibernate作为ORM框架,其核心功能是将Java对象映射到关系型数据库的表中,并将Java类的操作转换为SQL语句执行。这种映射机制不仅提高了代码的可读性和可维护性,还极大地减少了数据库操作的...

    Junit实战第二版 中文完整版.pdf

    JUnit简介 - **定义**:JUnit是一个广泛使用的Java单元测试框架,旨在简化测试过程并提高软件质量。 - **版本更新**:本书重点介绍了JUnit 4.8版本,该版本对Java开发流程进行了显著优化,包括对新应用程序类型的...

    接口测试白皮书--淘宝(中国)软件有限公司

    接口测试的技术简介 本节将简要介绍几种常用的接口测试技术和工具,包括: ##### 5.1 Junit Junit 是 Java 平台上的一个单元测试框架,广泛用于接口测试。它支持编写和运行自动化的测试案例,帮助开发者快速发现...

    JUnit_in_Action,_2nd_Edition.pdf

    #### 一、书籍简介与价值 《JUnit in Action, 2nd Edition》是一本深入介绍JUnit框架的专业书籍,适用于希望提高单元测试技能和软件质量意识的程序员。本书由Tahchiev、Leme、Massol 和 Gregory 合著,于2009年出版...

    junit和TestNG框架入门

    - **扩展性**:能够与第三方工具或框架(如Mockito、Dbunit等)良好配合,以支持模拟对象、断言和数据库操作等功能。 ##### 2. 测试框架的对比 - **JUnit**: JUnit是最早也是最广泛使用的Java单元测试框架之一,...

Global site tag (gtag.js) - Google Analytics