`
wuhua
  • 浏览: 2094992 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

单元测试总篇与TTD实践

阅读更多
        经过前几篇的测试学习跟实践,我觉得有必要对这次学习做个总结。其实上面的话只是幌子,主要原因还是javaeye的
lighter 写道
貌似这一篇文章要放在"agile"版块更好一些吧.
btw:wuhua同学写文章有时候可以把两篇结合成一篇,可能会更好一些,不然让别人看一篇文章要看一,二,三,四才能看完.个人建议而已,别见怪.

觉得他说的很对,当时是出于篇幅过程,怕javaeye blog不支持大篇幅的文章,所以拆开。不过我觉得我这个担心是多余的。这里说句题外话,我用过很多Blog,但觉得这里是最好的。速度快,写文章贴心(主要是对源代码格式化方面做的很出色)。

好了,进入正题。
先介绍下我以前写的那些文章先,让大家对这篇文章有个初步的认识。
单元测试之测试目的,
单元测试之实践一,关于设计的常见分层
单元测试之实践二,关于DAO的测试
单元测试之实践三 Service的测试
单元测试之实践四 Action的测试

以前我正常的设计流程是Database->Model -> Dao-> Service -> Action ->View。这样的设计伴随我1年多了,这样的设计方式好吗?这样的设计高效吗? 代码质量能保证吗? 我可以很肯定的回答,不能,如果数据库一该,我要在表格里面添加一个字段,或者什么的。那么它将会牵连到很多其他,修改的动作如下:Database->Model -> Dao-> Service -> Action ->View。 噢,my got,几乎跟设计的一样多,甚至更多,因为在修改的过程中你就算有再好IDE去重构它也不能保证它的正确性。然后你就要去测试,测试它的正确性。也许测试的过程将是修改过程的几倍时间。所以我个人觉得这样的设计方式是不高效的。总而言之就是这样的设计迟早会出问题的?

为什么会这样呢?难道就没有一种解决办法吗? 经过这段日子学习我发现,以前的设计不能很好的保证质量是因为你没有足够的单元测试去支撑着它,所以你改了代码后缺乏一个很好的手段去保持这段代码的质量,换句话的意思就是,没有一个静态的人去监督你的工作(我把单元测试比喻为静态的人,它只做一件事,就是督促你的代码不出问题)。

好了。我们已经找到了适合保证我们代码质量的方法了。但是我们还得提高我们的开发效率啊。这又怎么办呢?是不是还按照以前的方式吗?我想自己浑浑噩噩的活了20多年了。我想换种活法了,想找种更刺激,更有意义的生活方式。
设计有时候更生活是一样的,应该经常探索,经常实践才能感受的更多。
那好吧我们就来个彻底的变革吧。怎么变呢? 很明显:那就是TDD。
该怎么做呢?
以前的方式:Database->Model -> Dao-> Service -> Action ->View。
TDD的方式:Test->其他。
先看看下面Dao的例子吧:以前的方式:IBaseDao ->  BaseDao -> BaseDaoTest。
TDD:BaseDaoTest->IBaseDao->BaseDao.
 
  1. public void testFindAccountByName(){  
  2.     Account a = new Account("wuhua");      
  3.     ht.find("from Account as a where a.name=?", a.getName());  
  4.     List l = new ArrayList();  
  5.     l.add(a);  
  6.     control.setReturnValue(l);  
  7.     control.replay();  
  8.     Account result =  accountDao.findAccounByName(a.getName());  
  9.     Assert.assertEquals(a.getId(),result.getId());  
  10.     Assert.assertEquals(a, result);  
  11.     control.verify();  
  12.       
  13. }  
好,非常好,怎么这段代码不能运行呢?当然不行了,因为上面的很多类都没有。那我们这段代码的用途是什么呢?
用途就是:以为上面的从上面的代码我很清楚自己以后要做什么。1,要建立一个Model,里面起码有一个name属性,然后你会发现我们要测试的功能段是accountDao.findAccounByName(a.getName()); 里面我们要求测试的SQL是from Account as a where a.name=?,意图明确吧。好,

我们写下实际代码吧。
java 代码
  1. public Account findAccounByName(String name) {  
  2.         List l = this.getHibernateTemplate().find("from Account as ", name);  
  3.         if(l != null && l.size() >=1)  
  4.             return (Account) l.get(0);  
  5.         else   
  6.             return null;  
  7.     }  
好,代码写好了。去运行我们的测试吧。结果是令人失望的。怎么会是红色的呢。肯定是逻辑代码出问题了(如果测试代码没问题的话)。经过检查发现原来
from Account as a where a.name=?跟from Account as 完全两码事。好改回去

java 代码
 
  1. public Account findAccounByName(String name) {  
  2.         List l = this.getHibernateTemplate().
  3.                              find("from Account as a where a.name=?", name);  
  4.         if(l != null && l.size() >=2)  
  5.             return (Account) l.get(0);  
  6.         else   
  7.             return null;  
  8.     } 
怎么还是红色啊。我不干了(程序员暴躁的情绪出来了,我就经常这样)主管跟我说:“再查查吧。别灰心。”
后来查了半天发现原来
java 代码
 
  1. List l = new ArrayList();    
  2.  l.add(a);   
我只renturn一个预期的对象a
java 代码
 
  1. if(l != null && l.size() >=2)  
  2.             return (Account) l.get(0);  
  3.         else   
  4.             return null;  
而代码却要求我要传入预期两个对象才给我通过,所以代码只return null。

最后改了这段代码
java 代码
 
  1. public Account findAccounByName(String name) {  
  2.         List l = this.getHibernateTemplate().find("from Account
  3.                                         as a where a.name=?", name);  
  4.         if(l != null && l.size() >=1)  
  5.             return (Account) l.get(0);  
  6.         else   
  7.             return null;  
  8.     }  

终于通过了。绿色,绿色,我看到了。我对主管说。主管笑了。我也笑了

最后我郁闷下,写这篇文章足足话了我22个小时,
第一次写好了。杀毒突然重启。所以全没了。
第二次,提交不了。然后忘记备份,又全没了
第三次成功了。过程跟TDD差不多。



分享到:
评论
17 楼 yimlin 2007-08-29  
yiding_he 写道
楼主先把标题改一下吧,写错了。

另外,“Database->Model -> Dao-> Service -> Action ->View”的方式完全是搞反了,不符依赖倒置原则。我就是从页面开始写起,然后写 Action 和业务逻辑。


这个依赖导致原则不是这么用的吧!我的经验是:先设计Model,接着Service,然后才是Web层。我接触的项目看,Web层是一个集成模块,一个页面有可能访问到多个模块组件的数据。

16 楼 hlxiong 2007-08-29  
楼上的兄弟,LZ没有搞反。
从前台开始或是从后台开始,并没有绝对的要求,换言之,实际编码时两种方式都可以的。
比如,开发时leader可能会将前后台编码分开,有人专写后台,即service等业务逻辑处理;而有人专写前台,即页面、Action等。总不能要求每个人都View--Action--Service。。。。。吧?
而且,基本的model层对象发须先存在吧?我们都是把库建好然后自动生成pojo,dao....。
15 楼 yiding_he 2007-08-29  
楼主先把标题改一下吧,写错了。

另外,“Database->Model -> Dao-> Service -> Action ->View”的方式完全是搞反了,不符依赖倒置原则。我就是从页面开始写起,然后写 Action 和业务逻辑。
14 楼 topcloud 2007-08-28  
我现在主要集中在测试Service和DAO
做法是:
1.Service或DAO的接口(确定他们的行为)。
2.编写测试类。
3.编写实现类,填写处理代码。
4.测试---修改实现---测试
5.提交完了
13 楼 wuhua 2006-12-15  
意义就是测试你代码是否正确执行。
对啊写测试的时候差不多你写完测试,就想好了代码怎么实现。
只是用测试去驱动而已
12 楼 lewisou 2006-12-14  
这有什么意义啊?您写测试的时候已经想好怎么实现拉?
11 楼 wuhua 2006-12-14  
这段代码是主要测试:
from Account as a where a.name=?语句是否正确。
10 楼 lewisou 2006-12-14  
楼主第一段代码的

引用
ht.find("from Account as a where a.name=?", a.getName()); 

是干嘛用的?
9 楼 lighter 2006-12-14  
抛出异常的爱 写道
wuhua 写道
TDD最大的好处可能就是保证代码的质量,对于提高效率,我觉得没什么。
个人觉得开发效率最高的应该是asp了,因为存在大量的项目,对于一些简单的项目而已,只需修改下就ok了。
比如客户想要个商城,开始我并不认为全部重新开发是好的。虽然全部自己开发可以更好的控制质量,但是在效率方面还是上网找下,看看有没有适合客户需要的。如果有就在原来的基础上修改就OK了。

尽情利用网上资源估计是不错的选择。

作企业应用时....提心掉胆的用开源的代码
改来改去....最后疯掉...

一般情况,都不会大去升级开源的lib包,稳定才是最重要的,除非确定升级lib和版本能带来莫大的好处和方便...
8 楼 抛出异常的爱 2006-12-14  
wuhua 写道
TDD最大的好处可能就是保证代码的质量,对于提高效率,我觉得没什么。
个人觉得开发效率最高的应该是asp了,因为存在大量的项目,对于一些简单的项目而已,只需修改下就ok了。
比如客户想要个商城,开始我并不认为全部重新开发是好的。虽然全部自己开发可以更好的控制质量,但是在效率方面还是上网找下,看看有没有适合客户需要的。如果有就在原来的基础上修改就OK了。

尽情利用网上资源估计是不错的选择。

作企业应用时....提心掉胆的用开源的代码
改来改去....最后疯掉...
7 楼 wuhua 2006-12-14  
TDD最大的好处可能就是保证代码的质量,对于提高效率,我觉得没什么。
个人觉得开发效率最高的应该是asp了,因为存在大量的项目,对于一些简单的项目而已,只需修改下就ok了。
比如客户想要个商城,开始我并不认为全部重新开发是好的。虽然全部自己开发可以更好的控制质量,但是在效率方面还是上网找下,看看有没有适合客户需要的。如果有就在原来的基础上修改就OK了。

尽情利用网上资源估计是不错的选择。
6 楼 lighter 2006-12-14  
wuhua 写道
lighter 写道
"Assert.assertEquals(a.getId(),result.getId()); 
Assert.assertEquals(a, result);"
应当力保每个测试只有一个断言;在比较理想的状况下,setUp()构建预设环境,而每个测试针对这个预设环境只发出一个断言.


建议不错。在保证每个测试只有一个断言的条件下,必然会压迫代码更简单,逻辑更单一。
但有时候这并不现实

有时候真的不太现实,在一个测试出现多个断言情况或感觉测试有一些code smells的时候,我一般就会想到了重构,重构的时候只关心要重构的东西,而不添加新功能
5 楼 wuhua 2006-12-14  
lighter 写道
"Assert.assertEquals(a.getId(),result.getId()); 
Assert.assertEquals(a, result);"
应当力保每个测试只有一个断言;在比较理想的状况下,setUp()构建预设环境,而每个测试针对这个预设环境只发出一个断言.


建议不错。在保证每个测试只有一个断言的条件下,必然会压迫代码更简单,逻辑更单一。
但有时候这并不现实
4 楼 lighter 2006-12-14  
"Assert.assertEquals(a.getId(),result.getId()); 
Assert.assertEquals(a, result);"
应当力保每个测试只有一个断言;在比较理想的状况下,setUp()构建预设环境,而每个测试针对这个预设环境只发出一个断言.
3 楼 温柔一刀 2006-12-14  
步伐的大小是随着感觉来的
感觉好就大步前进,否则小步前进
呵呵
做到收发自如就好了
2 楼 wuhua 2006-12-14  
觉得有道路,估计看的人会比较辛苦。
1 楼 抛出异常的爱 2006-12-14  
跨度太大...
要一小步一小步的走
绿的次数太少了...

相关推荐

Global site tag (gtag.js) - Google Analytics