单元测试的艺术 : 第2版
本文关键词:单元测试的艺术,由笔耕文化传播整理发布。
> 其他综合 > 单元测试的艺术 : 第2版 1.3 集成测试 2014-08-08 11:20:04 我要投稿
本文所属图书 > 单元测试的艺术 : 第2版
本书是经典的单元测试学习指南,分四部分全面介绍了单元测试技术。第一部分阐述单元测试基本概念,包括如何使用测试框架。第二部分讨论破除依赖的高级技术:模拟对象、存根和隔离框架,包括重构代码以使用这些技 立即去当当网订购
任何测试,如果它运行速度不快,结果不稳定,或者要用到被测试单元的一个或多个真实依赖物,我就认为它是集成测试。例如,如果一个测试要使用真实的系统时间,真实的文件系统,或者一个真实的数据库,那这个测试就进入了集成测试的领域。
例如,如果一个测试不能控制系统时间,在代码中使用了当前时间DateTime.Now,那么每次测试执行使用的都是不同的时间,因此每次测试本质上都是不同的,那么这个测试就不稳定了。
这种测试本身并不是一件坏事。我认为集成测试和单元测试具有同等重要的地位,但是这两种测试应该彼此分开,以营造一种“绿色安全区”的感觉。这一点我会在本书后面的章节讨论。
如果一个测试使用真实的数据库,那么和那些只使用内存中的伪数据的测试相比,这种测试的行为痕迹更难以消除,从这个意义上说它就不是只在内存中运行了。这种测试的运行时间也会更长,这个问题也是无法控制的。单元测试运行应该很快。集成测试通常会慢很多。如果你有成百上千个测试的话,半秒钟都是至关重要的。
集成测试还可能带来另外一个问题:一次测试的东西太多。
如果汽车坏了该怎么办?先不说怎么修好它,你怎么找到问题出在哪呢?一个汽车的发动机由许多子系统组成,这些子系统协同工作,每个子系统都依靠其他的子系统的帮助产生最终的结果:一辆飞驰的汽车。如果汽车不动了,问题可能出在这些子系统中的任何一个,或者多个。这些子系统(或层次)的集成使得汽车能够工作。当汽车上路时,你可以把它能否开动看成是对这些部件的一个终极集成测试。如果这个测试失败了,那所有的部件就都失败了;如果这个测试成功了,那所有的部件也就都成功了。
软件也是同样的道理。大部分开发人员是通过用户界面的最终功能来测试软件的功能。单击一个按钮会触发一系列的事件,类和组件协同工作产生最终的结果。如果测试失败了,所有这些软件组件作为一个整体就失败了,而且很难找到到底是什么导致了整体操作的失败(参见图1-2)。
正如Bill Hetzel在The Complete Guide to Software Testing(Wiley,1993)一书中定义的,集成测试是“一个循序渐进的测试,软硬件相结合并进行测试直到整个系统集成在一起”。但是很多人每天做的不是系统集成测试,而是开发和单元测试, 这个定义并不太适用。
这里有一个更好的集成测试定义。
定义 集成测试是对一个工作单元进行的测试,这个测试对被测试的工作单元没
有完全的控制,并使用该单元的一个或多个真实依赖物,例如时间、网络、数据库、线程或随机数产生器等。
总的来说,集成测试会使用真实依赖物,而单元测试则把被测试单元和其依赖物隔离开,以保证单元测试结果高度稳定,还可以轻易控制和模拟被测试单元行为的任何方面。
1.2节中列出的问题可以帮助你认识到集成测试的一些缺点。我们接下来要定义期望在优秀的单元测试中看到的特质。
与自动化单元测试相比,非自动化集成测试的缺点
让我们把1.2节中的问题同样应用在集成测试上,同时思考在真实世界中使用单元测试的目的。
我两周前写的一个单元测试,今天还能运行并得到结果吗?几个月前写的呢?几年前写的呢?
如果回答是“不能”,那你怎么知道自己是不是已经破坏了以前实现的某个功能?在应用程序的生命周期中,代码经常会变化。如果在修改代码之后,你不能(或者不愿意)对之前所有的功能进行测试,就有可能破坏了某个功能而毫不知情。我把这种情况称为“偶然引入缺陷”。在软件项目快结束时,开发人员承受着压力修复已有的缺陷,“偶然引入缺陷”的情况会经常发生。有时开发人员会在修复旧缺陷的时候无意间引入新缺陷。如果在破坏功能后三分钟内就能发现问题,那该多好啊!在本书后面的章节中,你会了解如何做到这一点。
定义 回归是以前运行良好但是现在不工作的一个或多个工作单元。
我两个月前写的单元测试,团队里任何一个人都能运行它们并得到结果吗?
这个问题和上一个属于一个范畴,但比上一个问题要求更高。当你做改动时,,需要保证自己不会破坏别人的代码。许多开发人员都害怕修改以前系统中的遗留代码,就是担心不知道有什么别的代码依赖他们要改动的部分。简言之,他们不知道系统修改后的状态是否稳定。
应用程序是不是还正常工作是很令人担心的,尤其代码还不是你自己写的。如果知道自己不会破坏任何功能,你就比较有信心接手不太熟悉的代码了,因为有单元测试这个安全网。
优秀的单元测试可被任何人访问和运行。
定义 遗留代码在维基百科中定义为“与一个不再受支持或继续生产的操作系统,或其他计算机技术相关的源代码”,但是很多公司把任何比当前维护的应用更老旧的版本都称为遗留代码。这个词经常用来指代那些难以使用,难以测试,通常也更难以阅读的代码。
有一个客户曾经以一种很实际的方式定义遗留代码:“能运行的代码”。很多人喜欢把遗留代码定义为“没有测试的代码”。Michael Feathers在《修改代码的艺术》(Prentice Hall,2004)中把“没有测试的代码”作为遗留代码的正式定义,在阅读本书时我们也需要对此定义加以考虑。
我能在几分钟内跑完我写过的所有单元测试吗?
如果你不能很快运行完测试(几秒钟完成要好于几分钟完成),就不会经常运行它们(每天或者每周,有时甚至每月运行)。问题是,如果修改代码,你需要尽早得到反馈,好知道自己是不是破坏了什么功能。运行测试的时间间隔越长,你对系统做未测试的修改越多,出现问题的时候需要找寻缺陷的地方就越多。
优秀的测试需要能够快速运行。
我能一键运行我写过的所有单元测试吗?
如果不能,那可能意味着你需要对运行测试的机器进行配置,让测试能够正确运行(比如设置数据库的连接字符串),或者单元测试不是完全自动化的。如果不能完全自动化单元测试,你很可能会避免重复运行这些测试,团队里的其他人也一样。
没有人喜欢费工夫配置然后运行测试,而结果只是为了保证系统还能运行。开发人员有着更重要的任务,比如在系统中增加更多功能。
优秀的测试应该无需修改就能运行,不需要手工配置。
我能在几分钟内写出一个基本的测试吗?
辨别集成测试的一个最简单方法就是:集成测试需要花时间进行正确的准备和实施,不能直接执行。编写集成测试需要花费时间,因为它涉及内部,有时还有外部的依赖。(数据库可以看做外部依赖。)如果不对测试进行自动化,依赖就不是一个太大的问题,但是你也就失去了享受自动化测试所有好处的机会。编写测试的难度越高,你编写更多测试的可能性就越小,对所担心的“大问题”之外的东西也会关注越少。单元测试的一个特点就是会测试可能出问题的每一处细节,而不只是关注大问题。人们常常会惊讶:有很多缺陷正是在他们认为简单正确的代码里找到的。
当你只关注大的测试时,测试的逻辑覆盖率就会比较低,代码中核心逻辑的很多部分不会测到(虽然你可能覆盖到了较多的组件),这样就可能会出现没有考虑到的缺陷。
一旦找到了想用来测试具体对象模型的模式,你就应该能很快地轻松编写出优秀的测试。一个小小的警告:对一个以前没有做过单元测试的对象模型,即便是有经验的单元测试人员,也需要花30分钟或者更长时间才能写出第一个单元测试。这种摸索工作是难免的,也是预料之中的。对这个对象模型的第二个以及之后的测试应该很容易就能完成了。
到现在,我已经解释了什么测试不是单元测试,以及有用的测试应具有什么特征。基于这些,现在我可以开始回答这一章提出的主要问题了:什么是优秀的单元测试?
点击复制链接 与好友分享!回本站首页 您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力 上一篇:1.2 优秀单元测试的特性 下一篇:1.4 什么是优秀的单元测试 相关文章1.1 简介和CMMI入门
1.1.1 cmmi入门
1.1.2 短语“CMMI 符合性”在本书
1.2 敏捷方法入门
1.2.1 敏捷原则和实践
1.2.2 书中使用的敏捷术语
2.1 本章的学习内容
2.8.1 精简多余过程以缩短响应时间
2.10 了解CMMI模型的目的,帮助组织
2.11 使用CMMI模型时可以通过不同的
图文推荐本文关键词:单元测试的艺术,由笔耕文化传播整理发布。
本文编号:368416
本文链接:https://www.wllwen.com/wenshubaike/mishujinen/368416.html