锁定老帖子 主题:TDD很痛苦
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-02
iamlotus 写道 xyz20003 写道 DBUnit给我们带来的问题是,它不能自动处理外键关系,表间关系复杂时,每次insert都会报错失败。请问有何解决方案?
DBUnit还有个问题,你在自己测试中插入的数据(而非配置在文件中的)它是不会帮你删的。 正是应该以上原因,我们的数据框架是自己写的。 setup用SQL,自己保证顺序 tearDown后台跑一个存储过程,清空所有表 你没有领会DbUnit的妙处,或者说最佳实践。我记得DbUnit网站上有如下几条最佳实践: 1、每人一个数据库实例。同事之间互不干扰。 2、在运行测试用例前、后,数据库中表都是空的。 3、一个测试方法的运行成败,不能影响到其他测试方法。 回到你的问题,对程序插入的新数据,在测试方法的最后,要使用DbUnit提供的类,对这些数据进行删除。否则的话,在运行下一个测试方法时就可能出问题。 |
|
返回顶楼 | |
发表时间:2010-09-02
先谢谢jinjiankang同志了,之前也试过dbunit提供的对表自动排序,但是速度巨慢,到达无法忍受的地步了。后来遇到的问题更可悲,那就是自表关联的数据,死也倒不进去。
因为我们的测试数据是用dbunit从数据库里export出来的,所以自表关联的数据不一定是外键在前面。后来我们想了个办法,dbunit insert之前,用脚本清除所有外键,insert之后再全部加上。但是表结构一变就要死人啊。 最后就放弃了,用dbunit本来是为了可以自动导入导出,如果这么麻烦,还不如维护一套sql方便。 |
|
返回顶楼 | |
发表时间:2010-09-02
我们现在是这么做
使用spring-test+junit,可以自动回滚数据 单元测试用例基本都是用groovy写,效率提高不少 |
|
返回顶楼 | |
发表时间:2010-09-02
我们的系统要做单元测试也要准备一大堆的数据,其实这个准备过程倒也是可以接受的,但是最恐怖的是如果数据库的结构发生了调整,这些数据的初始化都要跟着改,这个工作量很大。
所以TDD一直是一个让我又爱又恨的东西。 |
|
返回顶楼 | |
发表时间:2010-09-03
最后修改:2010-09-03
dcross 写道 我们的系统要做单元测试也要准备一大堆的数据,其实这个准备过程倒也是可以接受的,但是最恐怖的是如果数据库的结构发生了调整,这些数据的初始化都要跟着改,这个工作量很大。
所以TDD一直是一个让我又爱又恨的东西。 可以试试dbdeploy这样的数据库版本控制工具,适合敏捷开发.但是前提是你们以程序为中心而不是数据库为中心。 另外觉得spring 对于测试的支持还不错。我们使用spring同样让数据回滚的方式。 |
|
返回顶楼 | |
发表时间:2010-09-03
dcross 写道 我们的系统要做单元测试也要准备一大堆的数据,其实这个准备过程倒也是可以接受的,但是最恐怖的是如果数据库的结构发生了调整,这些数据的初始化都要跟着改,这个工作量很大。
所以TDD一直是一个让我又爱又恨的东西。 看你怎么改变了,如果是整张表被drop,自然没办法。如果只改动某个字段你却要修改所有牵涉到这张表的数据,那说明你准备数据时插入了太多和测试无关的数据。 比如某张表 T (oid, c1,c2,...,c10) 如果你所有准备数据的方法都是这样 insert T (oid, c1,c2,...,c10) values (1,v1,v2,...v10)。那么一旦c1变成d1,确实所有地方都要修改。 可你真的在每个testcase中都会测到c1吗?不一定吧。 如果在测到c2,c3的地方你这样写insert T (oid, c2,c3) values (1,v2,v3)。那修改c就只会影响到确实测到c1的testcase,也只需修改这部分的准备数据,而不需要修改以上那条数据。 通常我反而会用这个特性,在改了某个字段后跑一遍testcase,看看究竟有多少地方需要修改。 当然,一般schema修改总归要谨慎。如果经常修改的话,可能要重新估量设计了。 |
|
返回顶楼 | |
发表时间:2010-09-03
jinjiankang 写道 iamlotus 写道 xyz20003 写道 DBUnit给我们带来的问题是,它不能自动处理外键关系,表间关系复杂时,每次insert都会报错失败。请问有何解决方案?
DBUnit还有个问题,你在自己测试中插入的数据(而非配置在文件中的)它是不会帮你删的。 正是应该以上原因,我们的数据框架是自己写的。 setup用SQL,自己保证顺序 tearDown后台跑一个存储过程,清空所有表 你没有领会DbUnit的妙处,或者说最佳实践。我记得DbUnit网站上有如下几条最佳实践: 1、每人一个数据库实例。同事之间互不干扰。 2、在运行测试用例前、后,数据库中表都是空的。 3、一个测试方法的运行成败,不能影响到其他测试方法。 回到你的问题,对程序插入的新数据,在测试方法的最后,要使用DbUnit提供的类,对这些数据进行删除。否则的话,在运行下一个测试方法时就可能出问题。 也就是说,把删除(程序)插入数据的责任交给编写testcase的人?我一个写testcase的人为什么要管这些东西?测试框架只要能保证运行每个testcase前数据库是空的,运行完数据库也空的。那么测试之间自然就不会相互影响了,干嘛还要我来保证把屁股擦干净? 我们以前也是由testcase自己擦屁股的,这样的好处是速度快。但实践中发现很不爽,因为我的testcase fail可能是由于你的屁股没擦干净,而你的testcase却没有问题。这样查起问题也很不方便。所以才改成由框架统一擦屁股,这样慢虽然慢一点,但能保证擦干净 |
|
返回顶楼 | |
发表时间:2010-09-03
最后修改:2010-09-03
aws 写道 我们现在是这么做
使用spring-test+junit,可以自动回滚数据 单元测试用例基本都是用groovy写,效率提高不少 自动回滚大多情况下没问题,不过对以下问题好像没什么好的解决方法 1)如果testcase fail,你没法在testcase上设个断点,然后用sqlplus去看看数据究竟是什么样的。 2)自动回滚只能回滚当前transaction,如果有个自治事务(取OID什么的)就回不去了。 3)如果你要测个存储过程该怎么解决呢? |
|
返回顶楼 | |
发表时间:2010-09-03
需要看数据可以在控制台打印出来,groovy做这种事情很方便
实在不行那就手动控制回滚 存储过程本身的逻辑测试用pl/sql developer调试基本就ok了 |
|
返回顶楼 | |
发表时间:2010-09-03
命令式风格(伪代码):
def add_record(): # 准备数据 my_obj=MyObj(foo=1,boo=2) # 存数据库 conn=get_db_conn() return conn.save(my_obj) 函数风格: def prepare_func(): return MyObj(foo=1,boo=2) def db_access_func(obj): conn=get_db_conn() conn.save(my_obj) def add_record(prepare_func,db_access_func): obj=prepare_func() return db_access_func(obj) 上述两种风格,显然函数风格的代码,对add_record函数更容易进行单元测试,原因是更容易建立mock: def test_add_record(): mock_prepare_func=lambda:1 mock_db_func=lambda x: 1 assert(1,add_record(mock_prepare_func,mock_db_func)) 是不是函数式风格的TDD要好一些... 有点爱上函数式风格了 ... |
|
返回顶楼 | |