论坛首页 综合技术论坛

[讨论]DBUnit(或类似框架)在实际项目中的使用情况

浏览 8669 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-08-21  
较早之前试用DBUnit作过一些简单的数据库单元测试。使用XML文件作为DataSet。DBUnit在测试前使用我提供的数据集,插入我们的测试数据库,测试完成后清理现场,这样做到每一个测试的数据库环境是可知、并且是一致、独立的。现 在,我的项目比较大,在中后期,想使用DBUnit进行单元测试并继续开发,即遇到了头痛的问题,数目较大的表结构,互相之间联系又多,准备测试数据是一个比较困难的事情;好吧,那我可以使用现成的数据,我备份出来一个运行中的数据库作为测试使用,幸好DBUnit可以通过数据库直接创建DataSet,这样我的策略就是,使用两个数据库,一个是源数据库,专门用来提供dataSet的,数据库里的数据稳定不变,可算是可知的。另一个数据库用来作测试,每一次测试就从源数据库复制数据到测试数据库,测完后清除测试数据库数据。想起来是件美事。嘿,可是当我准备好代码后执行一看,测试前复制数据库出的错不说,单说测试后清除数据就基本上不能实现,因为表间的关系,外键约束等,DBUnit还没有智能到去改变这些关系并删除数据。原先预想中的数据库准备的清除实现看来都相当困难了。我的计划看似只能中断在这里了。在这里查了一下,好久以前有人有过这样的问题了。不过事情过了好久,不知道是否有朋友在实际项目中使用了这个东西,或者,不限于DBUnit,都来说说自已平时在项目中,数据库单元测试是如何实现的吧。
   发表时间:2006-08-21  
继续我的尝试,有些新的心得。

我打算让我的测试数据是空数据库,那么在Setup的时候清除清据的工作就去到最少。于是我在源数据生成了一份Schema,用来创建了一个测试数据库。
开始测试,测试代码只是判断一是否等于一,目的是看看DBUnit能不能为我在测试数据库上为我创建跟源一样的数据罢了。异常抛出来了!“当 IDENTITY_INSERT 设置为 OFF 时,不能向表 'mytable' 中的标识列插入显式值。”。我跟踪源代码来到DBUnit的AbstractBatchOperation里面,在161行加入一句调试语句System.out.println(operationData.getSql());再次运行,看到了将被执行的插入语句,而id是其中的一个被插入字段。原来,那个表的ID是indentity的。不能被手动插入。再看了一下DBUint的代码,没发现它处理这个问题。而是假设可以把所有的数据都复制到新数据库里的。
测试往往会让我们发现一些不足,使用indentity不利于测试,而实际上也不利于数据库的移植,就算是同类型的数据库不同库的移植都很困难。所以,在设计数据库的时候,如果可以使用UUID就尽可能使用UUID。INDENTITY测试困难在于:
     不能正确插入ID信息,测试数据由可知变得不可知,也许你认为可以在测试数据库里关闭此ID的INDENTITY,测试数据变得可知,但是在程序里插入数据时却已经不能正常工作了。
     DBUnit的最佳实践是尽可能使用最小的数据集。大规模的插入和清除测试数据,一个导致测度效率低下,另一个可能发现不了一些隐藏的Bug,诸如插入某条数据我的测试代码预期是影响一张表,而实际上影响了两张表,这样,测试通过了,而隐藏的Bug却没有发现。
      继续尝试中。
0 请登录后投票
   发表时间:2006-08-21  
原来DBUnit提供了INDENTITY这种情况的处理方法的。在2.1版里。我使用的是MSSQL,对应的Operation类为:org.dbunit.ext.mssql.InsertIdentityOperation。它的文档上面写道:
This class disable the MS SQL Server automatic identifier generation for the execution of inserts.

If you are using the Microsoft driver (i.e. com.microsoft.jdbc.sqlserver.SQLServerDriver), you'll need to use the SelectMethod=cursor parameter in the JDBC connection string. Your databaseUrl would look something like the following:

jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb;SelectMethod=cursor

实际上需要自已去重写DatabaseTestCase的getSetUpOperation方法才能使用这个Operation:
protected DatabaseOperation getSetUpOperation() throws Exception {
        return InsertIdentityOperation.CLEAN_INSERT;
    }
0 请登录后投票
   发表时间:2006-08-21  
我原来也是遇到表结构互相之间联系较多的问题,后来是建立一个测试库把关系都删除了来做测试,然后最后还是去人工一下有关联关系的数据库再进行一下测试。
0 请登录后投票
   发表时间:2006-08-23  
YuLimin 写道
我原来也是遇到表结构互相之间联系较多的问题,后来是建立一个测试库把关系都删除了来做测试,然后最后还是去人工一下有关联关系的数据库再进行一下测试。

把数据库的关系去掉来做测试不可取啊。要测试只能保留原来的数据结构和关系。要的就是看程序去到真实的环境时是怎样的情况啊。去掉关系的测试是不可靠的。
0 请登录后投票
   发表时间:2006-12-12  
好像恢复表的时候可以指定先后顺序的。关联的表你就排一下先后顺序了。
关于IDENTITY的问题,我很早就已经抛弃自增长字段了,自己写了个类来生成流水号,每次生成100个,放在内存里。这样就不会有流水号的问题。
0 请登录后投票
   发表时间:2007-03-11  
如果测试数据库的数据很难删除,那么也就意味着 测试很难进行。测试很难进行也就意味着 测试的步骤有所不当。
最好是每次测试前能够保证数据库所有数据都是空的,然后每次测试的数据自己保证建立。

如果一些数据是共用的,那么就可以抽取成单独的dataset来处理。

如果测试中删除测试数据失败了,立即把这个问题作为错误来修正,
久而久之,就会养成好的习惯了。
0 请登录后投票
   发表时间:2007-03-13  
目前最有效的办法是利用脚本重建数据库。
测试前Drop表,Create表,进行测试。
所向无敌。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics