很多问题恰恰出在一些我们认为简单的代码中。除非是像一个JavaBean的getter和setter方法,因为这些方法可以通过IDE自动代码生成,没有必要为它编写测试。

  在项目开发中,我们需要经常通过重构来优化代码及改进我们的设计,当我们对代码进行重构之后,怎么能够保证代码仍然是正确的?那是运行所有被修改的代码的测试。如果测试通过,则说明我们的重构是正确。

  我们不能回避代码的维护问题。代码维护包括修正bug和增加功能。维护工作可能会距离代码编写完成有很长一段时间。当需要修改一个bug而修改 了代码,或增加一个新的功能而修改了代码时,又怎么能够保证修改后的代码仍然是正确的和没有隐患的呢?也许你会说,发布到应该服务器去测试知道了。笔者 曾经发生过因为维护而导致了更严重问题发生的情况。一个系统在生产环境正常运行很长时间了。某,业务人员要求修改某一个功能,笔者按业务的要求实现了 要修改的功能,业务也测试了修改后的功能,然后发布到了生产环境。程序下发两个星期后,报了一个非常严重的生产问题上来,以前能够正常运行的功能突然有问 题了,导致了大量的生产数据错误。这个问题是非常致命的,只能暂时停用系统。

  后我查明原因是,出错的模块与上次修改的代码有关联,上次修改时没有同时去修改现在出错的模块。要是我能够在修改代码后,运行所有的测试类,测试肯定会报告不通过。也不会把隐藏有这么严重错误的程序下发到生产环境去。

  我们看看没有写单元测试是怎么进行集成的。如果某些结果与我们所期望的不一致时,我们可能会在程序中加上许多 print语句,然后通过控制台来监视程序的运行过程。采用print语句并不能够保证我们的程序的正确性。好的情况是,它只能保证一条正确的路径,不 能保证其它的分支。另外当太多的print语句的信息在控制台上,也会让我们看不到想看到的信息,控制台的信息是有限的。在开发测试时,把调试信息打印在 控制台还可以接受,但是在生产环境,如果还有调试信息出现在控制台,那是不可以接受的。我们经常会忘记把调试的print语句及时的删除掉,从而影响 程序的性能。关键的是,print语句不能保证程序的正确性,也不能为你节省开发的时间。只会给你带来负面的影响。
 
  三、不知道怎么编写单元测试

  如果你相信单元测试的价值,那么去学习如何编写单元测试终会让你获益的。

  以java开发为例,junit这样的单元测试组件是非常易于学习和使用的。其它语言也有类似的单元测试组件。要相信这将是简单和能为你带来价 值的。但是笔者见过许多程序员编写的单元测试完全没有起到它应有的作用。这也与不知道怎么编写单元测试有关。所以我们应该掌握一些编写单元测试的基本原 则:

  应该为什么编写测试:虽然我们说为所有的代类都编写单元测试,但是测试JavaBean的setter或getter方法无异于是自寻烦恼。编写这样的测试完全是浪费时间。而且还增加了维护的困难。

  学会使用断言:断言是让我们为方法设置一个期望值。当方法执行结果与期望值不一致时,测试组件会报告测试不 通过。我见过一些项目的单元测试不是使用断言,而是自己编写一个打印(println)工具类,可以详细的在控制台中打印出类的详细成员信息,及集合的详 细信息。在单元测试中使用这个打印工具类来打印输出结果。这看起来好像非常不错。但是不应该使用这种方式来编写单元测试。

  使用打印工具类,需要程序员自已从控制台去观察程序的执行结果。当输出信息非常多时,控制台信息是无法向上翻屏的。所以不能够给我们提供更多的信息。所以这种方法也不能用于自动化测试。

  使用打印工具类,造成了一种假像,测试报告我们的测试总是成功的!如果使用断言,当方法的执行结果与我们设置的期望值不一致时,则会详细的报告测试失败的情况。

  使用打印工具来代替断言,造成测试的不充分,只会写出一个低测试覆盖率的测试。我们需要一个充分的测试。

  大化测试覆盖率:我们除了测试一个正确的路径外,我们还需要测试方法的每一个分支逻辑。需要编写尽可能多的测试程序逻辑的测试。写一个充分的测试。

  避免重复的测试代码:测试类也是非常重要的,与应用代码一样。测试类包含的重复代码越多,测试类自身出现的错误也会越多。而我们需要做的编码工作也越多。

  不要依赖于测试方法的执行顺序:使用Junit来进行单元测试,它不能保证测试方法按照我们的意图的顺序来执 行。当一个测试类有多个测试方法时,我们不能让一个测试方法必须在某一个测试之后执行才能成功。Junit不能为我们做这样的保证,我们不能依赖于测试方 法的执行顺序。

  针对接口测试:我们有“针对接口编程”的oo设计原则。同样对于测试,我们也需要针对接口测试。也是说在编写单元测试时,测试对象总是使用接口,而不是使用具体类。
 
  四、项目没有要求,所以不编写

  的确在很多项目中,团队并没有要求程序员为每一个类编写单元测试。反而会要求我们编写很多复杂的文档。作为程序员我们需要明白:程序员是编写单元测试的大受益者。

  这不是项目经理的事,也不是QA的事,而是程序员自身的事。因为单元测试是程序代码的一部份。单元测试是好的,有价值的文档,它应该与代码一起交付给客户。

  单元测试代码不是官僚,死板的文档。它是生动的,是程序员有用的文档。单元测试能够提高程序员对程序的信 心,能够使用养成良好的设计原则:“针对接口编程,而不是具体类”。因为要进行单元测试,所以我们需要让类独立于其依赖对象(使用Mock或stub)进 行测试。这迫使我们养成了良好的编程习惯。

  单元测试是改进我们设计的保证。做为一个的程序员,是会经常优化代码和设计,所以经常的进行重构。一个的程序员不能容忍异味代码。而单元测试是我们进行重构的信心保证。

  单元测试是一个日常开发活动,它贯穿于项目的整个生命周期。做一个负责任的程序员总是为自己的代码的质量负责的。是否经常改进你的设计,是否让别人很轻松的使用和修改你的代码。

  为所有类编写单元测试应该是一个程序员应具有的素质。项目有没有要求,不应当成为不编写单元测试的理由。