认为单元测试影响开发进度,一是借口,拒绝对单元测试相关知识进行学习(单元测试,代码重构,版本管理是开发人员的必备);二是单元测试是“先苦后甜”,刚开始搭建环境,引入额外工作,看似“影响进度”,但长远来看,由于程序质量提升、代码返工减少、后期维护工作量缩小、项目风险降低,从而在整体上赢了回来。
误解一:影响开发进度
一旦编码完成,开发人员总是会迫切希望进行软件的集成工作,这样他们就能够看到系统实际运行效果。这在外表上看来好像加快进度,而像单元测试这样的活动被看作是影响进度原因之一,推迟了对整个系统进行集成测试的时间。
在实践中,这种开发步骤常常会导致这样的结果:软件甚至无法运行。更进一步的结果是大量的时间将被花费在跟踪那些包含在独立单元里的简单Bug上面,在个别情况下,这些Bug也许是琐碎和微不足道的,但是总的来说,它们会导致推迟软件产品交付的时间,而且也无法确保它能够可靠运行。
在实际工作中,进行了完整计划的单元测试和编写实际的代码所花费的精力大致上是相同的。一旦完成了这些单元测试工作,很多Bug将被纠正,开发人员能够进行更高效的系统集成工作。这才是真实意义上的进步,所以说完整计划下的单元测试是对时间的更高效利用。
误解二:增加开发成本
如果不重视程序中那些未被发现的Bug可能带来的后果。这种后果的严重程度可以从一个Bug引起的用户使用不便到系统崩溃。这种后果可能常常会被软件的开发人员所忽视,这种情况会长期损害软件开发商的声誉,并且会对未来的市场产生负面影响。相反地,一个可靠的软件系统的良好的声誉将有助于一个软件开发商获取未来的市场。
很多研究成果表明,无论什么时候作出修改都要进行完整的回归测试,在生命周期中尽早地对软件产品进行测试将使效率和质量得到最好的保证。Bug发现得越晚,修改它所需的费用就越高,因此从经济角度来看,应该尽可能早地查找和修改Bug。而单元测试就是一个在早期抓住Bug的机会。
相比后阶段的测试,单元测试的创建更简单,且维护更容易,同时可以更方便地进行重构。从全程的费用来考虑,相比起那些复杂且旷日持久的集成测试,或是不稳定的软件系统来说,单元测试所需的费用是很低的。
误解三:我是个编程高手,无须进行单元测试
在每个开发团队中都至少有一个这样的开发人员,他非常擅长于编程,他开发的软件总是在第一时间就可以正常运行,因此不需要进行测试。你是否经常听到这样的借口?在现实世界里,每个人都会犯错误。即使某个开发人员可以抱着这种态度在很少的一些简单程序中应付过去,但真正的软件系统是非常复杂的。真正的软件系统不可以寄希望于没有进行广泛的测试和Bug修改过程就可以正常工作。编码不是一个可以一次性通过的过程。在现实世界中,软件产品必须进行维护以对功能需求的改变作出及时响应,并且要对最初的开发工作遗留下来的Bug进行修改。你希望依靠那些原始作者进行修改吗?这些制造出未经测试的代码的资深工程师们还会继续在其他地方制造这样的代码。在开发人员做出修改后进行可重复的单元测试,可以避免产生那些令人不快的负作用。
误解四:测试人员会测出所有Bug
一旦软件可以运行了,开发人员又要面对这样的问题:在考虑软件全局复杂性的前提下对每个单元进行全面的测试。这是一件非常困难的事情,甚至在创造一种单元调用的测试条件时,要全面考虑单元被调用时的各种入口参数。在软件集成阶段,对单元功能全面测试的复杂程度远远超过独立进行的单元测试过程。
最后的结果是测试将无法达到它所应该有的全面性。一些缺陷将被遗漏,并且很多Bug将被忽略过去。让我们类比一下,假设我们要清理一台电脑主机中的灰尘,如果没有把主机中各个部件(显卡、内存等)拆开,无论你用什么工具,一些灰尘还会隐藏在主机的某些角落无法清理。但我们换个角度想想,如果把主机每个部件一一拆开,这些死角中的灰尘就容易被发现和接触到了,并且每一部件的灰尘都可以毫不费力地进行清理。
单元测试之困境
测试在软件开发过程中一直都是备受关注的,测试不仅仅局限于软件开发中的一个阶段,它已经开始贯穿于整个软件开发过程。大家普遍认识到,如果测试能在开发阶段进行有效执行,程序的Bug就会被及早发现,其质量就能得到有效的保证,从而减少软件开发总成本。但是,相对于测试这个词的流行程度而言,大家对单元测试的认知普遍存在一些偏差,特别是一些程序员很容易陷入一些误区,导致了测试并没有在他们所在的开发项目中起到有效的作用。下面对一些比较具有代表性的误区困境进行剖析,并对于测试背后所蕴含的一些设计思考进行阐述,希望能够起到抛砖引玉的作用。
误区、困境一:使用System.out.print跟踪和运行程序就够了
这个误区可以说是程序员的一种通病,认为使用System.out.print就可以确保编写代码的正确性,无须编写测试用例,他们觉得编写用例是在“浪费时间”。使用System.out.print输出结果,以肉眼观察这种刀耕火种的方式进行测试,不仅效率低下,而且容易出错。
误区、困境二:存在太多无法测试的东西
在编码的时候,确实存在一些看起来比较难测试的代码,但是并非无法测试。并且在大多数情况下,还是由于被测试的代码在设计时没有考虑到可测试性的问题。编写程序不仅与第三方一些框架耦合过紧,而且过于依赖其运行环境,从而表现出被测试的代码本身很难测试。
误区、困境三:测试代码可以随意写
编写测试代码时抱着一种随意的态度,没有弄清测试的真正意图。编写测试代码只是为了应付任务而已,先编写程序实现代码,然后才去编写一些单元测试。表现出来的结果是测试过于简单,只走形式和花架,将大量Bug传递给系统测试人员。
误区、困境四:不关心测试环境
手工搭建测试环境,测试数据,造成维护困难,占据了大量时间,严重影响效率。对测试产生的“垃圾”不清除,不处理。造成测试不能重复进行,导致脆弱的测试,需要维护好测试环境,做一个“低碳环保”的测试者。
误区、困境五:测试环境依赖性大
测试环境依赖性大,没有有效隔离测试目标及其依赖环境,一是使测试不聚焦;二是常因依赖环境的影响造成失败;三是因依赖环境太厚重从而降低测试的效率(如依赖数据库或依赖网络资源,如邮件系统、Web服务)。