- 浏览: 184576 次
- 性别:
- 来自: 深圳
最新评论
-
mengfei86:
你们讨论的时候我刚上大学,。。。。、、现在都过去好多年了,。 ...
J2EE项目异常处理 -
di1984HIT:
文章不错,学习了
Ibatis读写CLOB数据 -
wulixiaodao:
main{
metodA();
}
详解spring事务属性 -
wulixiaodao:
Main{
Connection con=null;
...
详解spring事务属性 -
tao_gun:
感谢,有点懂了
详解spring事务属性
程序员为什么不写单元测试
袁光东
笔记曾经做过一次“程序员在项目开发中编写单元测试的情况”的调查。调查结果:
1. 严格的在项目中执行TDD 几乎没有
2. 为大部份业务方法编写单元测试,并保证方法测试通过。 占16.6%
3. 偶尔编写单元测试,一般情况下不写。 占58.3%
4. 为了应付项目检查而写单元测试,但并不保证方法是否测试通过。 占8.3%
5. 从来不编写单元测试。占16.6%
因为调查具有一定的局限性或片面性,调查结果并不十分精确。也基本能够反映国内程序员编写单元测试的状况。很少有程序员能够比较认真的去编写单元测试。那么到底又是什么原因呢?根据笔者参与的多个讨论,主要有下面几种原因使程序员不编写单元测试。
1. 为了完成编码任务,没有足够的时间编写单元测试。编写单元测试会导致不 能按时完成编码任务,推迟项目进度。
2. 单元测试的价值不高,完全是浪费时间。
3. 业务逻辑比较简单,不值得编写单元测试。
4. 不知道怎么编写单元测试。
5. 项目没有要求,所以不编写
6. 在项目的前期还是尽量去编写单元测试,但是越到项目的后期,就越失控。
测试常常是程序员十分厌倦的一个项目活动。测试能够为我们带来什么?了解这些非常的重要。测试不可能保证一个程序是完全正确的,但是测试却可以增强我们对程序的信心,测试可以让我们相信程序做了我们期望它做的事情。测试能够使我们尽量早的发现程序的bug.
一个bug被隐藏的时间的越长,修复这个bug的代价就越大。在《快速软件开发》一书中已引用了大量的研究数据。指出:最后才修改一个bug的代价是在bug产生时修改它的代价的10倍。
在这里,我们需要讨论的重点是单元测试。单元测试是一个方法层级上的测试,单元测试也是最细粒度的测试。用于测试一个类的每一个方法都已经满足了方法的功能要求。
在现代软件开发过程中,不管是xp还是rup都是十分重视单元测试。已经把单元测试作为贯穿整个开发周期的一项重要的开发活动。特别是在现代软件开发过程中,有经常集成和渐近提交的方法论。总结出了非常好的单元测试理论和实践:
在编写代码之前先编写单元测试,即测试先行
单元测试是代码的一部份,所有的代码必须有单元测试,并使测试通过。(像在Spring这些优秀的开源项目中在这方面做出了非常好的例子)
在修改代码之前先修改单元测试,并使它测试通过。
在编写代码之前先编写单元测试,会带来非常多的好处:
在编写代码之前先编写单元测试,并不是编写代码之前需要一次性为所有的类都事先编写单元测试。这需要有一个粒度的把握。最大的粒度应该控制在一个类级别上,最合适的粒度是控制在一个方法级别上。先为某一个方法编写测试代码,然后再为该方法编写实现代码,直到其测试通过后再为另一个方法编写测试代码,如此循环。单元测试在这里已经是一个契约规范了,它规范了方法应该做什么,实现什么。测试代码远远要比难以阅读和不会及时更新的需求文档更有价值。
测试先行,鼓励对需求的理解。如果没有理解需求,你是不可能写出测试代码的,当然你也不可能写出好的实现代码。
测试代码与其它文档相比会更有价值。当需求发生改变,实现代码也相应改变。而往往需求文档,设计文档得不到及时更新。测试代码相比那些过期的文档更具有价值。
测试先行可以编写出最大覆盖率的测试代码。如果在方法的实现代码编写完后再编写测试代码,这时开发人员总是编写一个正确路径的测试代码。它已经很难全面的去分析其它分支逻辑。
如果我们采用测试先行,那么就自动的完成了为所有的类都编写测试这个实践原则。为所有的类都编写测试会将为你带来非常多的好处:
我们可以很好的使用自动化测试来测试所有的类,特别是采用日构建的系统。
可以让我们放心的为类或方法添加新的功能。我们可以很容易的修改测试代码并验证修改后的代码是有用的代码。
可以让我们放心的对代码进行重构和进行设计优化。重构和设计优化通常会关联到多个类及多个方法。如果我们为所有的类都编写了测试,我们就可以在重构代码后很轻松的进行测试我们的修改是否正确。
为所有的类编写测试,可以让我们很容易的修改bug。当接到一个bug报告后,我们总是先修改测试代码,然后修改实现代码,使测试成功。这样不会因为修改一个问题而造成新问题的产生。
良好的单元测试策略给我们增强了对程序的信心,减少了bug的产生及bug的潜伏期。降低修改bug的代价。单元测试不会是项目开发周期的某一个生命周期,它贯穿于项目的整个生命周期,是一个非常重要的日常开发活动。
我们已经知道了单元测试是多么重要的。为什么程序员仍然不编写单元测试呢?为什么程序员总是有理由拒绝编写单元测试呢?
一、编写单元测试,增加了工作负担,会延缓项目进度?
这是笔者在多次讨论和调查中程序员拒绝编写单元测试的最多理由。“为了完成编码任务,没有足够的时间编写单元测试。编写单元测试会导致不能按时完成编码任务,推迟项目进度”。事实上真的是这样的吗?软件有着其特殊的生命周期,软件开发也具有特殊性。
首先,我们需要提供给用户的至少是一个能运行的产品。绝对不能是一堆不能运行的和充满了异味的哑代码。只有能够运行的,满足客户需求的代码才是真正有用的代码。这时代码就变成产品了。
很多程序员只关注编写代码的完成时间,而乎略了调试代码,集成及修改和维护时间。
很多程序员只关注编写代码的完成时间,而乎略了调试代码,集成及修改和维护时间。
如果没有单元测试,开发活动会是这样的情景。
以一个web应用开发为例:业务代码编写完成->打包->发布到服务器->进行功能测试->发现问题->修改代码->再打包……如此循环。
任何一个web程序员对于这种开发情景都不会感到陌生。往往不断的打包,发布,功能测试的时间是代码编写的10倍以上。通过集成系统来发现程序的bug,我们往往很难一下子准确的定位bug产生的地方。应用服务器提供的错误信息对于我们来说是非常有限的。
如果为每一个类都编写单元测试并让每一个方法测试通过,又会是怎么样的开发情景呢?
编写测试代码->编写业务代码->运行测试方法->修改代码让测试通过->所有的类都通过测试->打包->发布到服务器->进行功能测试->发现bug->修改测试代码->修改业务代码->测试通过->再打包…如此循环。
从上面的过程显而易见,我们需要花费更多的编码时间。因为需要为每一个业务类编写测试代码。但是它并不会导致我们总体需要花费更多的时间。我们只是可以非常轻松的在ide环境中运行测试方法。在代码尚未打包发布之前我们就已经确保了业务代码的正确性。当我们把所有通过测试的代码集成到应用服务器后,出现错误的机率要少得多。当集成测试后发现bug时,我们也总是先修改测试类。保证在集成之前所有的类都经过测试通过。这样功能测试的时间就成数量级的减少,所以总的花费时间要比没有单元测试要少得多。
另外,如果没有单元测试,会经常出现一些低级的错误,如拼写错误,空指针异常等。就因为一个小小的拼写错误而需要重新打包,发布一次。如果有单元测试,就可以避免这些低级的错误。
如果没有单元测试,把代码集成到应用服务器后再发现错误时,我们往往更多的是凭借自己的经验来判断问题出在哪里。对于没有经验的程序员来说只能是撞运气了。这就像是瞎子走路一样,两眼一把黑。如果每个类都有单元测试,就无需要这么痛苦了。
这使得我回想起当年做网络系统。当时的局域网络都是采用环状网络,还没有现在的交换机来组星形网络。环状网络的传输网络采用同轴细缆线,网络中的所有节点都在一条主干线上,网络的两端都会加上一个电阻来形成一个环。
环状网络的最大的缺点就是当任意一个节点有固障时,整个网络都不能连通。维护这种网络是非常麻烦的。通常采用得比较多的方法就是“切香肠”法。把最后一个电阻取下来,接到第二台电脑的网络节点的末端,检查两条线是否能连通。连通后再把电阻取下来到第三台电脑的网络节点的末端,连上第三台电脑。这样来依次检查整个网络的线路。
后来发展了星形网络,也是现在局域网普遍采用的。有一台交换机,每一台电脑连接到交换机,任意一个节点网络故障不会影响到其它节点,检查起来就非常方便了。没有单元测试的代码就像是环状网络,而有测试的代码就像星形网络。
其次,有可能我们第一次编写的代码是没有问题的,但是到后来需求改变而修改了其中某些类的代码,把它发布到了应用服务器去测试,所要修改的内容已经测试通过了。但是因为某些类的修改导致了其它类不能正常的工作。这种bug往往隐藏得非常深,因为只要不触动它,它就不会出现。可能会程序发布到生产环境之后才会被业务人员发现。如果每个类都有测试代码,我们在打包之前运行所有测试代码,就可以很容易的发现因为代码修改带来的连带性错误。
其三,在离bug产生越近,修正bug就越容易;在bug产生越远,修正bug的代价就越昂贵。假设我们去集成一个星期(甚至更长时间)前编写的代码,当发现问题时,我们已经忘掉了很多重要的实现细节,所以修改变得困难重重。
编写单元测试,并不会加重程序员的负担,反而提高了程序员对程序的信心,大大的减少了重复打包,发布,纠错误的时间。这些花费的时间远远要比编写单元测试花费的时间多几个数量级。编写单元测试,可以让你更容易和更放心的去修改代码,增加功能从而加快了项目的开发进度。
为什么我们总是要主观的去认为编写单元测试会延缓项目进度呢?与其痛苦的挣扎,还不如去尝试一下好的实践。
二、业务逻辑简单,不值得编写单元测试
程序员是聪明的,程序员也总是自认为是聪明的。认为一些业务逻辑比较简单的类不必要编写单元测试。我们必须承认,需求不断变化,我们也必须要有勇气去接受需求变化。编写单元测试的另一个目的就是拥抱变化,而不是拒绝变化。编写单元测试就是提高了我们对程序的信心。在敏捷软件开发中,代码为集体所有,项目组的任何一个人都可以去修改任何一个代码文件。每当我要去修改一个别人编写的代码时,我总是多么的希望有程序的单元测试代码,而往往都让我非常的失望。一般我都得花费很大的力气去猜想原作者的原始意图。也许你会说:“你可以去看需求文档啊!你不会去看注释吗?”。但实际情况是,当需求文档完成了它的使命后,开发人员就把它扔到了一边了,文档总是过期的。没有几个项目组能够使得需求,设计这些文档与最新实现代码保持一致。所以去看一个过期的文档是没有价值的。注释也同样,保持最新仍然是一个最大的问题,并且注释能够提供的信息是非常有限的。所以我最需要的就是看测试代码了。测试代码最能反映出方法最新的功能契约。由代码的编写者去写的单元测试要比由其它人去编写的单元测试要更完善,更准确。
很多问题恰恰就出在一些我们认为简单的代码中。除非是像一个JavaBean的getter和setter方法,因为这些方法可以通过IDE自动代码生成,没有必要为它编写测试。
在项目开发中,我们需要经常通过重构来优化代码及改进我们的设计,当我们对代码进行重构之后,怎么能够保证代码仍然是正确的?那就是运行所有被修改的代码的测试。如果测试通过,则说明我们的重构是正确。
我们不能回避代码的维护问题。代码维护包括修正bug和增加功能。维护工作可能会距离代码编写完成有很长一段时间。当需要修改一个bug而修改了代码,或增加一个新的功能而修改了代码时,又怎么能够保证修改后的代码仍然是正确的和没有隐患的呢?也许你会说,发布到应该服务器去测试就知道了。笔者曾经发生过因为维护而导致了更严重问题发生的情况。一个系统在生产环境正常运行很长时间了。某一天,业务人员要求修改某一个功能,笔者按业务的要求实现了要修改的功能,业务也测试了修改后的功能,然后发布到了生产环境。程序下发两个星期后,报了一个非常严重的生产问题上来,以前能够正常运行的功能突然有问题了,导致了大量的生产数据错误。这个问题是非常致命的,只能暂时停用系统。
最后我查明原因是,出错的模块与上次修改的代码有关联,上次修改时没有同时去修改现在出错的模块。要是我能够在修改代码后,运行所有的测试类,测试就肯定会报告不通过。也就不会把隐藏有这么严重错误的程序下发到生产环境去。
我们看看没有写单元测试是怎么进行集成的。如果某些结果与我们所期望的不一致时,我们可能会在程序中加上许多print语句,然后通过控制台来监视程序的运行过程。采用print语句并不能够保证我们的程序的正确性。最好的情况是,它只能保证一条正确的路径,不能保证其它的分支。另外当太多的print语句的信息在控制台上,也会让我们看不到想看到的信息,控制台的信息是有限的。在开发测试时,把调试信息打印在控制台还可以接受,但是在生产环境,如果还有调试信息出现在控制台,那是绝对不可以接受的。我们经常会忘记把调试的print语句及时的删除掉,从而影响程序的性能。最关键的是,print语句不能保证程序的正确性,也不能为你节省开发的时间。只会给你带来负面的影响。
三、不知道怎么编写单元测试
如果你相信单元测试的价值,那么去学习如何编写单元测试最终会让你获益的。
以java开发为例,junit这样的单元测试组件是非常易于学习和使用的。其它语言也有类似的单元测试组件。要相信这将是简单和能为你带来价值的。但是笔者见过许多程序员编写的单元测试完全没有起到它应有的作用。这也与不知道怎么编写单元测试有关。所以我们应该掌握一些编写单元测试的基本原则:
应该为什么编写测试:虽然我们说为所有的代类都编写单元测试,但是测试JavaBean的setter或getter方法无异于是自寻烦恼。编写这样的测试完全是浪费时间。而且还增加了维护的困难。
学会使用断言:断言就是让我们为方法设置一个期望值。当方法执行结果与期望值不一致时,测试组件就会报告测试不通过。我见过一些项目的单元测试不是使用断言,而是自己编写一个打印(println)工具类,可以详细的在控制台中打印出类的详细成员信息,及集合的详细信息。在单元测试中使用这个打印工具类来打印输出结果。这看起来好像非常不错。但是不应该使用这种方式来编写单元测试
使用打印工具类,需要程序员自已从控制台去观察程序的执行结果。当输出信息非常多时,控制台信息是无法向上翻屏的。所以不能够给我们提供更多的信息。所以这种方法也不能用于自动化测试。
使用打印工具类,造成了一种假像,测试报告我们的测试总是成功的!如果使用断言,当方法的执行结果与我们设置的期望值不一致时,则会详细的报告测试失败的情况。
使用打印工具来代替断言,造成测试的不充分,只会写出一个低测试覆盖率的测试。我们需要一个充分的测试。
最大化测试覆盖率:我们除了测试一个正确的路径外,我们还需要测试方法的每一个分支逻辑。需要编写尽可能多的测试程序逻辑的测试。写一个充分的测试。
避免重复的测试代码:测试类也是非常重要的,与应用代码一样。测试类包含的重复代码越多,测试类自身出现的错误也会越多。而我们需要做的编码工作也就越多。
不要依赖于测试方法的执行顺序:使用Junit来进行单元测试,它不能保证测试方法按照我们的意图的顺序来执行。当一个测试类有多个测试方法时,我们不能让一个测试方法必须在某一个测试之后执行才能成功。Junit不能为我们做这样的保证,我们不能依赖于测试方法的执行顺序。
针对接口测试:我们有“针对接口编程”的oo设计原则。同样对于测试,我们也需要针对接口测试。也就是说在编写单元测试时,测试对象总是使用接口,而不是使用具体类。
四、项目没有要求,所以不编写
的确在很多项目中,团队并没有要求程序员为每一个类编写单元测试。反而会要求我们编写很多复杂的文档。作为程序员我们需要明白:程序员是编写单元测试的最大受益者。
这不是项目经理的事,也不是QA的事,而是程序员自身的事。因为单元测试是程序代码的一部份。单元测试是最好的,最有价值的文档,它应该与代码一起交付给客户。
单元测试代码不是官僚,死板的文档。它是生动的,是程序员最有用的文档。单元测试能够提高程序员对程序的信心,能够使用养成良好的设计原则:“针对接口编程,而不是具体类”。因为要进行单元测试,所以我们需要让类独立于其依赖对象(使用Mock或stub)进行测试。这就迫使我们养成了良好的编程习惯。
单元测试是改进我们设计的保证。做为一个优秀的程序员,是会经常优化代码和设计,所以经常的进行重构。一个优秀的程序员绝对不能容忍异味代码。而单元测试就是我们进行重构的信心保证。
单元测试是一个日常开发活动,它贯穿于项目的整个生命周期。做一个负责任的程序员总是为自己的代码的质量负责的。是否经常改进你的设计,是否让别人很轻松的使用和修改你的代码。
为所有类编写单元测试应该是一个程序员应具有的素质。项目有没有要求,不应当成为不编写单元测试的理由。
五、为什么越在项目的后期,单元测试就越难以进行下去?
在很多项目的初期,项目中的大部分程序员都能够自觉的去编写单元测试。随着项目的进展,任务的加重,离交付时间越来越近,不能按时完成项目的风险越来越大,单元测试就往往成为牺牲品了。项目经理因为进度的压力也不重视了,程序员也因为编码的压力和无人看官而不再为代码编写单元测试了。
笔者所有亲历的项目都着像这么糟糕的情况发生。越是在项目的后期,能坚持编写单元测试的程序就在整个项目组中不会超过15%。为了追赶进度,绝大多数程序员都把没有经过任何测试的代码提交到版本服务器,项目经理也不再追问,照单全收。这样做的结果就是在后期,集成花费的时间越来越多,几个技术骨干人员只得日夜加班进行系统集成。好不容易集成完了之后,下发给测试人员测试时,bug的报告成数量级的增长。程序员就日以继夜的修改bug.还有非常多的bug被隐藏更深,一直潜伏到生产环境去。项目中,越来越多的人对项目失去信心,每一个人都在抱怨,数不清的bug,修正了一个bug,更多的bug报告上来。
每天都在修改bug,但是每天又会报告上更多的bug。于是开始有人想逃离了,有人请假,也有人离职。当项目总算结束时,每一个的内心都清楚,项目太烂了,还有很多的错误还没被测试出来,赶快逃离这个项目组吧!一半的人病倒了,或对项目的维护失去了信心。
为什么会这样?有没有宣导测试的重要性呢?
在项目初期应该进行宣导单元测试的重要性。
有没有做过相关的培训工作?在项目启动时,需要进行一些相关的培训,教授团队成员最基本的编写单元测试的技巧。
有没有做过相应的风险防范?越是工作资历越深的程序员,就越会拒绝编写单元测试,他们总是有太多的理由来拒绝编写单元测试。这些顽固的老程序员往往负责着核心的代码的编写。我们知道20-80定律吧。80%的错误是发生在20%的代码之中的,往往最严重的错误就发生在那些老鸟们的代码中。有没有在事先就做好风险防范,说服他们编写单元测试。
有没有做好测试相关的基础工作。有没有针对不同类型的程序编写测试基类,让编写测试变成一项非常简单的工作。有一些代码是依赖于特定的环境,如EJB访问,JNDI访问,web应用程序依赖Servlet API等。测试这些程序是非常困难的。应该编写一些测试基类和测试stub,让这些程序可以脱离于特定环境就像普通程序一样进行单元测试。让普通程序员轻松的编写测试代码进行程序测试。
可以实行日构建和测试覆盖率检查,没有通过测试的代码绝不允许放到版本服务器。检查测试的覆盖率。
在现代软件开发过程中,测试不再作为一个独立的生命周期。单元测试成为与编写代码同步进行的开发活动。单元测试能够提高程序员对程序的信心,保证程序的质量,加快软件开发速度,使程序易于维护。不管测试先行还是测试后行,没有单元测试那是绝对不行的。
弱者为失败找理由,强者为成功找方法!今天你单元测试了吗?
评论
127 楼
hax
2007-08-21
smartpay2007 写道
只想鄙视你这个变态王...
你他们的脑子有病,如果有问题就去华山医院精神科去治疗
谢谢合作..
另外,以后别发一些无聊的帖子,要是想傻傻,请去大街上,要是想做技术的,比如研究,SAP与Websphere Portal 欢迎发帖子!!
你他们的脑子有病,如果有问题就去华山医院精神科去治疗
谢谢合作..
另外,以后别发一些无聊的帖子,要是想傻傻,请去大街上,要是想做技术的,比如研究,SAP与Websphere Portal 欢迎发帖子!!
骂谁呢?楼上激动的话都讲不清楚了。。。发生什么了?
126 楼
smartpay2007
2007-08-21
只想鄙视你这个变态王...
你他们的脑子有病,如果有问题就去华山医院精神科去治疗
谢谢合作..
另外,以后别发一些无聊的帖子,要是想傻傻,请去大街上,要是想做技术的,比如研究,SAP与Websphere Portal 欢迎发帖子!!
你他们的脑子有病,如果有问题就去华山医院精神科去治疗
谢谢合作..
另外,以后别发一些无聊的帖子,要是想傻傻,请去大街上,要是想做技术的,比如研究,SAP与Websphere Portal 欢迎发帖子!!
125 楼
ddppfamily
2007-08-21
我发现我周围的一些程序员一般都是在软件界里面混饭吃的,程序是好是坏根本就无所谓,只要能实现用户的需求,并且不出错就行了,所以单元测试根本就是可有可无的东西。
124 楼
wandou
2007-08-20
根本原因,还是领导不行啊。领导不懂技术,但是可以拿到项目。不懂技术,就招不到懂技术的程序员,因为他本人不识货,很容易被人糊弄,而夸夸其谈之辈,往往在领导眼里更有能力。所以。。。。就这么一路腐烂下来了。
导致现在还有这么多人讨论要不要单元测试。唉。。。素质啊。。。。
导致现在还有这么多人讨论要不要单元测试。唉。。。素质啊。。。。
123 楼
gengjw
2007-08-12
不写单元测试不是公司管理的问题,因为这个是对程序员有好处的,TDD能够提高程序员开发效率的,理由楼主已经说的很清楚了,不再解释!
根据我的经验原因有三:
1.不知道写单元测试的好处。
2.不知道怎么写单元测试。
3.知道单元测试工具(如JUNIT)怎么用,但是严重缺乏设计能力,导致自己写的模块无法测试(高耦合,低内聚)。
前两个原因好办,如果是第三个原因,赶快学习OO和设计模式吧,提高自己的设计能力。
根据我的经验原因有三:
1.不知道写单元测试的好处。
2.不知道怎么写单元测试。
3.知道单元测试工具(如JUNIT)怎么用,但是严重缺乏设计能力,导致自己写的模块无法测试(高耦合,低内聚)。
前两个原因好办,如果是第三个原因,赶快学习OO和设计模式吧,提高自己的设计能力。
122 楼
fool_leave
2007-08-10
好贴
也说说我的意见
1:提到log4j、junit和ant
我也做了很多年的项目开发
log4j不是一定要用,我对log4j感觉不好,所以很早以前就自己写了一个log工具。但log对于service来说很必要,尤其运行期间。所以能不能够很好的记录log是很关键的。至于什么样的log工具看自己习惯了。我已经习惯于用自己的工具了。
junit也不错
不过不是不用它就说明你菜的。它能够提供的单元测试功能很有限。我觉得用main函数也可以代替。只不过有点麻烦。不过是习惯不同而以。重点在于测试方法体怎么写
ant我也不是很熟。
很多IDE里都有封装了的打包运行工具。由于我一直在windows下编程,所以ant不怎么用。
2:注释
我从来不觉得注释是非要不可的
如果你是提供一个API或者一个公用方法,注释就很必要
但也不是
这种注释意义不大
可以参考很多工具api的注释,里面不但写明了方法作用,参数,还会讲述如何使用、注意事项和一些基本原理,这才是重要的
而对于内部一些类,与其像上面那样写注释,不如把变量名取好
3:单元测试
这个是重中之重
我觉得应该讨论几点
1)如何做单元测试
2)单元测试如何评定
3)单元测试的粒度怎么掌握
这三点不弄清楚,单元测试就像一层雾一样,很多程序员都会觉得似乎碰到了它,可又不知道是不是真的在里面
1)其实我也期待lz可以快点把它弄出来
对于一个小项目的一个方法
这个做单元测试,谁都会
可如果复杂一点的方法,比如用户数据系统
得到处于工作状态的用户,能够通过性别,年龄和区域查询
public ArrayList getBusyUsers(int maleType,int ageLine,Local local){
}
这个方法可能在一个系统里只是一个功能性的小方法,却需要数据库、运行服务等配合,如果遇到多服务,那就更麻烦了。而对于一个系统来说,类似于这样的单元测试更重要,也更有意义。
我们可以把这样的方法拆分成无数个小方法,对每个小方法作测试,可是这样测出的结果和组合后的结果会有差别的。
2)一个单元测试是不是成功,怎么个评价方法呢?
简单的例子
对于这样一个最简单的例子,测试者先写测试代码,因为他简单,所以预先设计了一组数字,测试和预想完全一样,测试成功。
可是,当a2=0的情况没有考虑到,结果bug遗漏。
为了避开因为经验不足和考虑不周全而产生的遗漏,test case 需要可以尽量罗列可能的数值。这样测试程序一下子就复杂了。而对于这个小方法,使用一个很庞大的测试程序,会让程序员感到杀鸡用牛刀。最终也会放弃测试了。
3)粒度问题
其实说来说去都离不开这个粒度问题
粒度小,测试内容就很多,在测试代码上需要花的时间就多。而对于大粒度的东西,如我1)里提到的业务逻辑部分,单元测试就非常复杂。这样出现的结果是。
1很多程序员为了单元测试而单元测试,避开大逻辑部分,而是对小模块方法来测试,结果真正需要单元测试的被遗漏了
2在对小模块的单元测试中,如2)中提到的例子,因为单元小,所以测试写的不完全,结果每次测试都似乎无用,降低了单元测试的必要性(对程序员的感觉上)
最终单元测试从一个代码历程里分离出来。
再考虑到时间和个人对工作量的把握上有点出入,慢慢的就会走向由单元测试要求,变为只有在感觉上需要的时候才去测试。
这些是我的看法,也是我的经历。
我想,除非在一个很成熟的开发环境下:大家都做单元测试;项目不会因为时间问题而赶工;项目下来时就考虑到测试时间;程序员在平时不会因为每天的任务量而加班;项目结束后不是可以运行就可以上线,而是要有很高的效率和稳定性才可过关。不然做到每个case or function都要test是很难的。
也说说我的意见
1:提到log4j、junit和ant
我也做了很多年的项目开发
log4j不是一定要用,我对log4j感觉不好,所以很早以前就自己写了一个log工具。但log对于service来说很必要,尤其运行期间。所以能不能够很好的记录log是很关键的。至于什么样的log工具看自己习惯了。我已经习惯于用自己的工具了。
junit也不错
不过不是不用它就说明你菜的。它能够提供的单元测试功能很有限。我觉得用main函数也可以代替。只不过有点麻烦。不过是习惯不同而以。重点在于测试方法体怎么写
ant我也不是很熟。
很多IDE里都有封装了的打包运行工具。由于我一直在windows下编程,所以ant不怎么用。
2:注释
我从来不觉得注释是非要不可的
如果你是提供一个API或者一个公用方法,注释就很必要
但也不是
/** * 记录数据到本地文件 * @param data 数据 * @param path 文件位置 */
这种注释意义不大
可以参考很多工具api的注释,里面不但写明了方法作用,参数,还会讲述如何使用、注意事项和一些基本原理,这才是重要的
而对于内部一些类,与其像上面那样写注释,不如把变量名取好
3:单元测试
这个是重中之重
我觉得应该讨论几点
1)如何做单元测试
2)单元测试如何评定
3)单元测试的粒度怎么掌握
这三点不弄清楚,单元测试就像一层雾一样,很多程序员都会觉得似乎碰到了它,可又不知道是不是真的在里面
1)其实我也期待lz可以快点把它弄出来
对于一个小项目的一个方法
public double plus(double a1,double a2){ return a1+a2; }
这个做单元测试,谁都会
可如果复杂一点的方法,比如用户数据系统
得到处于工作状态的用户,能够通过性别,年龄和区域查询
public ArrayList getBusyUsers(int maleType,int ageLine,Local local){
}
这个方法可能在一个系统里只是一个功能性的小方法,却需要数据库、运行服务等配合,如果遇到多服务,那就更麻烦了。而对于一个系统来说,类似于这样的单元测试更重要,也更有意义。
我们可以把这样的方法拆分成无数个小方法,对每个小方法作测试,可是这样测出的结果和组合后的结果会有差别的。
2)一个单元测试是不是成功,怎么个评价方法呢?
简单的例子
public double divide(double a1,double a2){ return a1/a2; }
对于这样一个最简单的例子,测试者先写测试代码,因为他简单,所以预先设计了一组数字,测试和预想完全一样,测试成功。
可是,当a2=0的情况没有考虑到,结果bug遗漏。
为了避开因为经验不足和考虑不周全而产生的遗漏,test case 需要可以尽量罗列可能的数值。这样测试程序一下子就复杂了。而对于这个小方法,使用一个很庞大的测试程序,会让程序员感到杀鸡用牛刀。最终也会放弃测试了。
3)粒度问题
其实说来说去都离不开这个粒度问题
粒度小,测试内容就很多,在测试代码上需要花的时间就多。而对于大粒度的东西,如我1)里提到的业务逻辑部分,单元测试就非常复杂。这样出现的结果是。
1很多程序员为了单元测试而单元测试,避开大逻辑部分,而是对小模块方法来测试,结果真正需要单元测试的被遗漏了
2在对小模块的单元测试中,如2)中提到的例子,因为单元小,所以测试写的不完全,结果每次测试都似乎无用,降低了单元测试的必要性(对程序员的感觉上)
最终单元测试从一个代码历程里分离出来。
再考虑到时间和个人对工作量的把握上有点出入,慢慢的就会走向由单元测试要求,变为只有在感觉上需要的时候才去测试。
这些是我的看法,也是我的经历。
我想,除非在一个很成熟的开发环境下:大家都做单元测试;项目不会因为时间问题而赶工;项目下来时就考虑到测试时间;程序员在平时不会因为每天的任务量而加班;项目结束后不是可以运行就可以上线,而是要有很高的效率和稳定性才可过关。不然做到每个case or function都要test是很难的。
121 楼
jive
2007-08-10
fishinlove 写道
项目开发不规范,程序员天天加班围着项目转,没有那么多的精力去写。
正解。。。项目需求不断变更,人员流动大。。。
归结到一点,项目流程不规范。。。
以上是部分原因。。。
120 楼
抛出异常的爱
2007-08-10
ooezez 写道
根本原因还是我们自身的业务素质还不够啊
根本原因还是不想尝试新的编程态度啊。。。。
119 楼
ooezez
2007-08-10
根本原因还是我们自身的业务素质还不够啊
118 楼
抛出异常的爱
2007-08-09
难于测试的代码一般是由于框架,业务不熟悉
楼上所说的大约是由于先写代码所导致的。PS:重覆就意味着重构。
楼上所说的大约是由于先写代码所导致的。PS:重覆就意味着重构。
117 楼
lyliu
2007-08-09
唉,过犹不及,单元测试如是, 注释亦如是
本人见过最过份的单元测试是对Java Bean的每个get,set都做单元测试
本人见过最过份的单元测试是对Java Bean的每个get,set都做单元测试
116 楼
zjh666qq
2007-08-09
做好单元测试,可以在后面的测试阶段少很多bug,很重要的。楼主的话很有道理,强烈支持
115 楼
yiding_he
2007-08-09
代码是产品的最终设计,产品的质量和代码的质量有直接关系。不认识到这一点,程序员是不会认真对待代码的。
114 楼
joachimz
2007-08-08
还在期待LZ的“如何做单元“(How)。<br/>
<br/>
对于单元测试的意义,我觉得大部分人都会认可。但肯定有很多困难,只有帮助分析和解决这些困难,才能真正地推动单元测试。<br/>
<br/>
以我自己为例,我一直希望能在项目和团队中推行单元测试,但是各种环境、设计问题,常常导致测试实际难以推行,目前我只能尽量灌输一些面向测试的设计和开发,让一些有复杂逻辑的程序尽量少的与环境榜定,便于测试。<br/>
<br/>
但由于我们系统架构上是采用分布式,大量采用无状态服务的设计思路,服务于服务之间相互依赖严重,因此如果做单元测试,有大量的Mock工作要做,感觉代价太大,成果不多。<br/>
但另一方面,如果为了测试,通过重构,抽离业务逻辑脱离环境,又很困难,会给程序带来一些不必要的复杂性。<br/>
<br/>
期待更多人能分享一些自己工作中的实践经验,或者例子。
<br/>
对于单元测试的意义,我觉得大部分人都会认可。但肯定有很多困难,只有帮助分析和解决这些困难,才能真正地推动单元测试。<br/>
<br/>
以我自己为例,我一直希望能在项目和团队中推行单元测试,但是各种环境、设计问题,常常导致测试实际难以推行,目前我只能尽量灌输一些面向测试的设计和开发,让一些有复杂逻辑的程序尽量少的与环境榜定,便于测试。<br/>
<br/>
但由于我们系统架构上是采用分布式,大量采用无状态服务的设计思路,服务于服务之间相互依赖严重,因此如果做单元测试,有大量的Mock工作要做,感觉代价太大,成果不多。<br/>
但另一方面,如果为了测试,通过重构,抽离业务逻辑脱离环境,又很困难,会给程序带来一些不必要的复杂性。<br/>
<br/>
期待更多人能分享一些自己工作中的实践经验,或者例子。
113 楼
yurer
2007-08-08
习惯了只看不说了。
不过今天看到讨论这么积极的,还是忍不住登陆下。
一个项目的成败,并非绝对以测试代码,注释力度为准则的。
在项目周期内,完成开发范围内的内容,基本就能拿到钱。
不过,提交给客户的产品,和自己开发过程的附属物,完全两码事。
注释,是一个代码的有益补充,如果代码流程写真的写的非常的清晰,那么要注释来做什么?代码本身就是最好的注释。
例如,我用struts来做项目,那么我的action里,每个方法的request,response,mapping等参数,难道都非要写上注释么?没必要吧。懂struts的人不需要注释也能看懂,不懂的给注释也看不懂。
看不懂?那先去看struts去。代码本来就是给懂代码的人看的。
当然如果你写一段复杂的业务逻辑,你能一句注释都没有么?
注释只是陪衬红花的绿叶而已。
至于测试,我倒觉得非常有必要,单元测试更是如此。
不过至于测试方式,倒是没必要规定必须用什么,这个本来就是跟开发环境,方式,周期等项目本身的特点决定的,不能一概而论。
不过今天看到讨论这么积极的,还是忍不住登陆下。
一个项目的成败,并非绝对以测试代码,注释力度为准则的。
在项目周期内,完成开发范围内的内容,基本就能拿到钱。
不过,提交给客户的产品,和自己开发过程的附属物,完全两码事。
注释,是一个代码的有益补充,如果代码流程写真的写的非常的清晰,那么要注释来做什么?代码本身就是最好的注释。
例如,我用struts来做项目,那么我的action里,每个方法的request,response,mapping等参数,难道都非要写上注释么?没必要吧。懂struts的人不需要注释也能看懂,不懂的给注释也看不懂。
看不懂?那先去看struts去。代码本来就是给懂代码的人看的。
当然如果你写一段复杂的业务逻辑,你能一句注释都没有么?
注释只是陪衬红花的绿叶而已。
至于测试,我倒觉得非常有必要,单元测试更是如此。
不过至于测试方式,倒是没必要规定必须用什么,这个本来就是跟开发环境,方式,周期等项目本身的特点决定的,不能一概而论。
112 楼
Godlikeme
2007-08-02
关于重构,关于文档,关于注释的文章已经讨论很多了,就不要在人家帖子里在重复、重复,再重复了。
111 楼
lewisou
2007-08-02
javaTo 写道
稍微复杂点的逻辑可能会写个测试,说是测试,其实就是加个main方法,而且这个main方法最后还可能被无情的删除。
如果说测试是一种责任,那么我不得不说一下我们公司,注释啊,同志们!
公司的底层数据库操作是自己的框架,再加一层service,那个注释写的,跟没写一样,看起来真叫累,所以现在我写代码注释都打的非常详细。
如果说不写测试是不负责任,那么不写注释的同志们就该拉出去痛打一顿!
如果说测试是一种责任,那么我不得不说一下我们公司,注释啊,同志们!
公司的底层数据库操作是自己的框架,再加一层service,那个注释写的,跟没写一样,看起来真叫累,所以现在我写代码注释都打的非常详细。
如果说不写测试是不负责任,那么不写注释的同志们就该拉出去痛打一顿!
照我看,狂写注释的人应该好好反审一下。
正常情况下,注释写的太多说明代码中类似i,k,j的变量太多,或者是因为一个方法充斥着太多莫名奇妙的让人费解的循环或者条件判断。这样的代码需要的不是注释而是重构! 在代码经过多次重构之后,一段段费解的代码被移到适当的方法或类中,程序逻辑变得清晰。此时更无加注释的需要,因为那个时候加的所有注释都只是方法名和类名的中文翻译。。。如果你认为重构后的代码仍然需要注释,那只可能有一个原因。你英语不够好,方法名都用的是拼音,或者是别人用英语写的方法名你看不懂。这种情况下我建议你去花点时间学英语,或是装个金山词霸。
综上推理,写代码狂写注释的人需要去学如何重构。
110 楼
netpcc
2007-07-23
Godlikeme 写道
netpcc 写道
说到文档,JavaDoc并不是什么好的代表吧。
绝大多数JavaDoc都没有任何参考价值。里面全是废话。
就连JDK的JavaDoc也不怎么样。大部分的所谓说明都无意义。
就文档而言我是推崇MSDN的。从原理到step by step到具体某一典型需求的实现方法。详细的参考文档。无数的代码片断,以及完整的Sample程序。
而且MSDN虽然是英语文档,但是充分考虑到非英语母语人群。里面的英语非常易懂。
总之就一个词:专业
不过能做到这个程度的确实是凤毛麟角。
至于说直接读源代码,一方面对程序员要求太高,另一方面效率太低。我读一个50K的Heritrix的源代码都花了2个月的时间。很多细节都没有读到。要是大家都这么干的话,成本就到天上去了。
而C++的源代码,比如STL,Boost,cryptopp等,只有真正的高手才能读懂他们的源代码了。这样的人一个公司里能有多少?
绝大多数JavaDoc都没有任何参考价值。里面全是废话。
就连JDK的JavaDoc也不怎么样。大部分的所谓说明都无意义。
就文档而言我是推崇MSDN的。从原理到step by step到具体某一典型需求的实现方法。详细的参考文档。无数的代码片断,以及完整的Sample程序。
而且MSDN虽然是英语文档,但是充分考虑到非英语母语人群。里面的英语非常易懂。
总之就一个词:专业
不过能做到这个程度的确实是凤毛麟角。
至于说直接读源代码,一方面对程序员要求太高,另一方面效率太低。我读一个50K的Heritrix的源代码都花了2个月的时间。很多细节都没有读到。要是大家都这么干的话,成本就到天上去了。
而C++的源代码,比如STL,Boost,cryptopp等,只有真正的高手才能读懂他们的源代码了。这样的人一个公司里能有多少?
java有源代码还说那么多干什么?doc只是一个概述。
java有源代码那是很后来的事了。
而且读源代码的效率真是。。。
109 楼
experience
2007-07-22
其实说是成本问题也未尝不可,因为“通常”(注意我说的是通常)不写单元测试的程序员要便宜一些。
唉,不知道又要得罪多少人,我闪了。。。
唉,不知道又要得罪多少人,我闪了。。。
108 楼
Godlikeme
2007-07-21
netpcc 写道
说到文档,JavaDoc并不是什么好的代表吧。
绝大多数JavaDoc都没有任何参考价值。里面全是废话。
就连JDK的JavaDoc也不怎么样。大部分的所谓说明都无意义。
就文档而言我是推崇MSDN的。从原理到step by step到具体某一典型需求的实现方法。详细的参考文档。无数的代码片断,以及完整的Sample程序。
而且MSDN虽然是英语文档,但是充分考虑到非英语母语人群。里面的英语非常易懂。
总之就一个词:专业
不过能做到这个程度的确实是凤毛麟角。
至于说直接读源代码,一方面对程序员要求太高,另一方面效率太低。我读一个50K的Heritrix的源代码都花了2个月的时间。很多细节都没有读到。要是大家都这么干的话,成本就到天上去了。
而C++的源代码,比如STL,Boost,cryptopp等,只有真正的高手才能读懂他们的源代码了。这样的人一个公司里能有多少?
绝大多数JavaDoc都没有任何参考价值。里面全是废话。
就连JDK的JavaDoc也不怎么样。大部分的所谓说明都无意义。
就文档而言我是推崇MSDN的。从原理到step by step到具体某一典型需求的实现方法。详细的参考文档。无数的代码片断,以及完整的Sample程序。
而且MSDN虽然是英语文档,但是充分考虑到非英语母语人群。里面的英语非常易懂。
总之就一个词:专业
不过能做到这个程度的确实是凤毛麟角。
至于说直接读源代码,一方面对程序员要求太高,另一方面效率太低。我读一个50K的Heritrix的源代码都花了2个月的时间。很多细节都没有读到。要是大家都这么干的话,成本就到天上去了。
而C++的源代码,比如STL,Boost,cryptopp等,只有真正的高手才能读懂他们的源代码了。这样的人一个公司里能有多少?
java有源代码还说那么多干什么?doc只是一个概述。
发表评论
-
一个特殊的异常处理
2008-12-13 23:59 1403一个特殊的异常处理 文:袁光东 一、业务需求说明 前段时间接 ... -
Spring JavaConfig开发指南(下)
2007-06-03 10:56 6559... -
Spring JavaConfig开发指南(上)
2007-06-03 10:25 7788Spring JavaConfig开发指南 作者:袁光东 1. ... -
ThreadLocal与synchronized
2007-05-22 17:49 27422ThreadLocal与synchronized Java良好 ... -
倒底该怎么写DAO的单元测试?
2007-05-17 16:17 14060public void testAddUserInfo() ... -
详解spring事务属性
2007-05-10 22:55 20456Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我 ... -
Ibatis读写CLOB数据
2007-04-25 16:43 22893Ibatis是一个高效,方便,易于学习的数据访问组件,在性能上 ... -
细说框架风云 JSF能否拯救WEB江湖
2007-04-24 18:08 2082细说框架风云 JSF能否拯救WEB江湖 Java ... -
模板方法模式实现探讨
2007-04-23 18:30 4431模板方法(Template Method) ... -
Spring架构设计-增强MultiActionController
2007-04-20 12:04 4838Spring架构设计-增强MultiActionControl ... -
让Spring架构减化事务配置
2007-04-19 12:20 4692让Spring架构减化事务配置 注:原创文章,本文曾发表于it ... -
J2EE项目异常处理
2007-04-18 12:19 16423J2EE项目异常处理 ...
相关推荐
程序员为什么不写单元测试?[1]单元测试工具赛门铁克误杀门事件在一片争议声中落下了帷幕,但是它身后隐蔽的问题还远未结束,诺顿误杀彰显测试价值的回归,同时也向广大的程序员们敲响了警钟,不做单元测试的程序员在...
程序员为什么不写单元测试?[2]单元测试工具一个bug被隐藏的时间越长,修复这个bug的代价就越大。在《快速软件开发》一书中已引用了大量的研究数据指出:最后才修改一个bug的代价是在bug产生时修改它的代价的10倍。在...
1.2. **预防回归错误**:当修改代码或添加新功能时,单元测试可以确保原有功能不受影响。 1.3. **文档作用**:测试用例可以作为代码功能的文档,帮助理解代码预期行为。 1.4. **支持重构**:在代码重构过程中,单元...
《程序员修炼三部曲之单元测试》是一本深入探讨软件开发中单元测试技术的重要书籍,尤其对于.NET、AJAX、C#、Java和VB.NET等技术领域的开发者来说,更是不可多得的参考资料。单元测试是软件开发过程中的一个重要环节...
Java程序员在进行软件开发时,单元测试是必不可少的一环,以确保代码的正确性和稳定性。Junit4作为Java领域中最常用的单元测试框架,是每个Java开发者必须掌握的技能之一。这篇压缩包文件中的"Junit4教程.doc"文档,...
一大早,一个年轻的程序员问大师:“我准备写一些单元测试用例。代码覆盖率应该达到多少为好?”大师回答道:“不要考虑代码覆盖率,只要写出一些好的测试用例即可。” 一大早,一个年轻的程序员问大师: “我准备...
在RTT(Real Time ThreadX)操作系统环境下,单元测试的重要性不减。虽然RTT是实时操作系统,但其内核组件和用户应用程序同样需要经过严格的测试。通过单元测试,开发者可以确保每个任务、中断服务例程或内核服务的...
单元测试通常由程序员自己执行,通过功能测试(黑盒测试)和代码测试(白盒测试)来验证模块的正确性。黑盒测试关注的是软件功能是否符合需求,而白盒测试则侧重于程序的内部逻辑是否正常运行。 黑盒测试是一种不...
这解释了为什么在软件发布前才进行测试会有那么多问题。大多数错误都未被发现,而且修正已发现错误的代价如此之大,以至于你必须有选择地进行处理,因为根本不可能全部修复。 使用PHPUnit进行测试与你曾经的做法...
JUNIT软件测试软件测试技术JUnit和单元测试入门简介软件测试1、几个相关的概念白盒测试——把测试对象看作一个打开的盒子,程序内部的逻辑结构和其他信息对测试人员是公开的。回归测试——软件或环境的修复或更正后...
很多程序员认为单元测试会花费大量的时间,因此他们写单元测试的意愿比较低,导致了单元测试很难被推广开来。究其原因,主要集中在意识、认知、方法、态度四个问题上。而这本教程,很好地解决了这些问题:什么是单测...
微软的VS开发工具为我们提供了强大的单元测试环境,在VS当中可以直接对类库项目进行测试,极大的方便了程序员的自我纠错能力。除了官方的解决方案之外,还有一种非常好的免费开源的第三方测试工具,那就是NUnit。它...
Unit是一个Java语言的单元...Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。
《单元测试之道Java版:使用JUnit》PDF 下载
单元测试作为软件开发过程中的一个重要组成部分,对于提高软件质量和维护性具有不可替代的作用。本文将深入探讨如何在Visual Studio环境中进行C++单元测试,并分析单元测试的重要性和常见误区。 #### 二、单元测试...
单元测试是一种软件开发的最佳实践,它鼓励程序员对每个函数、类或模块编写独立的测试用例,以便在修改代码或添加新功能时确保现有代码的行为不受影响。CppTest库提供了丰富的断言机制,使得测试编写简单而直观,...
【程序员写单元测试】: 程序员参与单元测试编写有助于他们更好地理解代码逻辑,提高代码质量。未来,随着对软件质量要求的提升,不编写单元测试的程序员可能会面临更大的挑战。 总结:单元测试是保证软件质量的...