`
gavin213
  • 浏览: 33653 次
  • 性别: 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  
非常感谢 ,照着文档入门,修改几个地方后,可以跑了,谢谢

相关推荐

    数据库操作的单元测试

    1.1. DBunit的简介 1 1.1.1. DBunit简单介绍和原理 1 1.1.2. DBunit的三大核心组件 1 1.1.3. DBunit的安装使用 2 1.2. HSQLDB简介 3 1.2.2. 什么是HSQLDB 3 1.2.3. HSQLDB安装和使用 5 1.2.4. HSQLDB使用 7 1.2.5. ...

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

    2009/8/31 ...5 接口测试的技术简介 51 Junit 52 DbUnit 53 Spring TestContext Framework 54 Unitils 55 TestNG 56 CruiseControl 57 Clover 58 Mock 6 接口测试的方向 7 参考资料 8 作者介绍

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

    项目简介: 租房网是公司旗下的一个公寓直租平台。用户可以在上面发布房源,租客可以很轻松的在平台上找到符合自己需求的住房。 核心模块: 后台管理系统、用户服务、登录注册服务、住房出租服务、写字楼出租服务、...

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

    项目简介:智慧社区是由福建中网物联科技有限公司专门为社区服务专门打造的一个信息管理系统。主要是一个针对物业部门对住宅小区内的建筑、住户、设备、人员等信息进行综合管理的一个信息管理系统。核心功能:物业...

    Unitils框架与模块扩展

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

    Spring.3.x企业应用开发实战(完整版).part2

    2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 2.3.2 UserDao 2.3.3 LoginLogDao 2.3.4 在Spring中装配DAO 2.4 业务层 2.4.1 ...

    Spring3.x企业应用开发实战(完整版) part1

    2.1.2 实例功能简介 2.2 环境准备 2.2.1 创建库表 2.2.2 建立工程 2.2.3 类包及Spring配置文件规划 2.3 持久层 2.3.1 建立领域对象 2.3.2 UserDao 2.3.3 LoginLogDao 2.3.4 在Spring中装配DAO 2.4 业务层 2.4.1 ...

Global site tag (gtag.js) - Google Analytics