如果说你我之间有什么相似之处的话,那就是你可能阅读过大量文章,在其中作者主张测试驱动开发(TDD,Test-Driven Development)或者其他涵盖了广泛测试(无论是单
元测试还是集成测试层面上)的开发实践。我认为,关于这些实践的许多主张缺乏实际项目经验,很难让人相信他们的观点。事实上,当我们把这些非常严格的测试实践应用于大
型项目上时,通常它们根本无法顺利工作。
在本文中,我将说明一些关于测试的常见误解。我希望,如果你在编写测试时也存在这样的误解,那么本文能帮助你和你的团队来判断何时适合测试,何时不适合测试。
误解一:测试可以表明我的代码是正确的!
虽然这种误解在直觉上是正确的,但是你确实无法依赖测试来建立任何形式的具有严格正确性的标准。每当你编写了一个测试,你就已经测试了程序中的一种可能情况。当程
序中存在许多单元时,或许存在无限多种(或是多得难以应付的)可能的情况需要测试时,那么测试所有可能情况是不可行的——因此,典型的对策是测试一些出错情况、边界情
况以及若干恰好确保一切正常的“常规”情况。
如果你的目标是正确性,那么上面谈到内容还远不足以满足要求。尽管程序仍存在许多bug,但是开发一套总是可以通过的测试还是相当容易的。然而有些bug根本不可能通过
测试检查出来——其中竞争条件和包括并发性在内的其他错误都是经典的例证,即使你已经对调度程序进行控制,然而可能的交错操作的数量增长是如此之快,以至于可靠地测试
很快成为了不可能完成的任务。
因此,测试无法展示所有情况下的正确性,除非是在最普通的情况下,那样我们可以在测试中完全指定程序单元的行为。对于这些普通情况,往往不值得从一开始就编写测试
;之所以说这些情况实在是太普通了,是因为我们所要测试的代码本身就是微不足道的!通过为那些微不足道的代码片段编写测试只完成了一件事,那就是增加维护开销,并且为
测试机增加工作量。
既然测试也只是一些代码,那么在你的测试中同样可能存在bug。如果编写测试与编写代码的是同一个人,那么他们往往可能错误地实现一个程序单元,然后编写一个确保那个
错误行为能够通过的测试。此问题的根源在于开发者误解了规格说明,而不是实现过程中犯下的小错误。
如果你确实需要保证正确性,那么请对你的代码进行形式化验证(目前的验证工具要比过去好得多)。如果你不需要保证正确性,那么编写测试就可以了。须牢记,编写测试
的作用就如同烟雾报警器对于火灾的作用一样,其实它并不能检测出各种各样的问题。
误解二:测试是可执行的规格说明!
基于以下几个原因我认为这个观点是错误的。先来看看在我的字典里规格说明的定义:
一组需求,用于界定对于某一对象或过程的准确描述。
因此,如果我的代码符合规格说明的要求,那么它就应该是完全正确的,因为规格说明准确界定了代码的行为。如果说我的测试是规格说明,那么必须进而证明测试的正确性
。正如我们已经讨论过的,测试并没有做这样的事情,因此测试不是规格说明。
让我们看下实际情况,假设一名开发者通过阅读测试用例可以推断出某个函数的预期行为,然后引入一大堆含混不清的测试用例;如果测试用例不够全面,那么我们可能最终
推断出错误的结论,有时可能与预期行为仅有细微差别。
此外,对于测试用例并未进行一致性检查。也就是说,由于开发者失误或误解,因此你的测试可能实际“指定”了一个非预期的行为。这可能会导致在你的测试中出现一些矛
盾,因此也可以说你的规格说明中出现了矛盾。
随机测试软件,例如QuickCheck,会让编写测试的工作变得非常简单,就像本应包含的布尔属性一样,而且该软件会为你生成测试用例。该软件使得测试更接近于可执行的规
格说明,不过它仍然不会对属性进行一致性检查。
误解三:测试会让我们拥有良好的设计!
当让一个糟糕的设计可以测试时,此设计仍然具有改进的可能,因此测试不是优良设计实践的替代品。当为系统接口编写大量的测试时,实际上是增加了开发者投入在那些接
口上的“工作投资”。当这些接口不再是最佳选择时问题就会随之产生,即开发者已经为那些接口编写了大量测试。改变接口也就意味着改变所有与之配套的测试。由于测试与那
些接口紧密耦合在一起,因此其中大多数测试将必须被废弃并重写。既然大多数开发者的成长依附于他们所从事的工作,这会导致在项目的生命周期中对于那些次优的设计决策踌
躇不前,尽管那些决策不是最适合的。
在这里给出的解决方案是,只有在你编写了一系列原型之后再开始着手测试。这样你就不必为测试那些可能在稍后会被大量重构的代码而焦虑。对于开发者和测试机而言,所
做的一切都是在增加工作量,而且当需求或接口改变时,开发者必须销毁数小时的工作成果,这会使他们更心痛。而如果你不等待而进行了测试,那么你的测试实际上会导致糟糕
的设计,因为开发者将不愿进行任何重大的重构。
此外,让代码可以测试很困难。通常人们仅仅为了让测试更加容易而采用有问题的设计决策;尝试大量模拟接口实现,或者是编写具有大量代码的测试用例,以至于测试用例
代码本身几乎也需要测试,这些做法都暴露出对于抽象的泄漏(mock对象和stub往往会经受此问题的折磨)。
误解四:测试会让更改代码更容易!
测试并不总是让更改代码更容易,然而,如果你正在对底层接口实现进行修改,那么测试可以帮助你捕获新实现中的功能衰退或非预期的行为。如果你正在对程序的更高层次
结构进行修改,然而这种对立的情况则是更普遍的现象。测试通常与更高层次接口紧密耦合。改变这些接口就意味着重写测试。在那种情况下,你让自己活得很辛苦——你将必须
重写那些测试,从而给自己增加了更多的工作,而且之前的旧测试对于确保你没有引入功能衰退而言无能为力,这意味着测试根本帮不上忙。
所以,不写测试?我没有说你不应该编写测试。对于提高信心以及阻止软件功能衰退而言,测试是一种有价值的方式。然而,测试无法统一带来优良的设计、正确性、技术规
格说明或者轻松地重构,至于原因如上所述。过度使用测试会让开发变得*更难*而不是更容易。
同样,根本不验证代码会让质量保证无从谈起,不过会让快速构建原型更轻松。测试在质量保证与灵活性之间引入了一个权衡问题,所以我们必须在二者之间做出适当的妥协
。
译者评论
俗话说“尺有所短寸有所长”,此话与“No silver bullet”有异曲同工之妙。既然世间没有包治百病的灵丹妙药,那么就应对症下药,而且下药前最好弄明白药品的功效及
禁忌,否则吃错药的后果不堪设想。
言归正传,测试的“功效”不可否定,但对其“禁忌”的说明却没有那么清晰。本文作者提出了几点对于测试“禁忌”的看法,或许个别观点有失偏颇,但是其目的是希望大
家可以“更加客观、全面地认识TDD及测试”。
免费自动化测试工具:http://www.spasvo.com/
分享到:
相关推荐
- **等价类划分**:将输入数据分为若干等价类,只需为每个等价类设计一个测试用例。 - **边界值分析**:关注数据边界,因为边界往往是问题多发的地方。 - **因果图法**:用于处理多个输入条件组合的影响,帮助找出...
其中,等价类划分是一种常见的方法,它将输入数据划分为若干个等价类,只需为每个等价类选择一个代表性的数据进行测试。这种方法可以显著减少测试用例的数量,但要求我们精确地识别出等价类。 边界值分析则是另一种...
在实际操作中,建议将软件开发过程划分为若干阶段,包括理解需求分析、功能定义、接口定义、功能模块/函数划分、功能模块/函数初始化及功能实现、功能模块/函数接口衔接及限制、功能模块/函数功能测试及代码规范确认...
11. **关于软件测试的误解** - **知识点**:软件测试常见误区。 - **解释**:软件测试无法证明软件的绝对正确性;测试员需要具备良好的沟通技巧;QA(质量管理)与Testing(测试)虽然密切相关,但它们的目标和...
这些题目通常分为若干部分,如简单排序、搜索、图论问题、动态规划等,难度逐渐递增,旨在逐步挑战学生的编程能力。 "普及组测试数据" 这部分文件则包含了用于检验程序正确性的输入输出样例。在编程竞赛中,测试...
2. **语言和语法**:在测试需求规格说明书中,发现了若干语病和用词不当的情况,如“的”与“地”的使用,以及表述不通顺的问题。这提示我们需要注重文档的清晰性和准确性,避免引起误解。 3. **需求明确性**:测试...
- **优点**:V模型反映了软件从需求定义到实现与测试活动之间的关系,强调在整个软件项目的生命周期中需要经历的若干开发与测试级别的对应关系。 - **缺点**:在编码完成后才进行测试,可能导致缺陷较晚被发现;开发...
测试数据通常由若干部分组成,包括题目描述、输入样例、输出样例以及可能的限制条件。这些数据是评估参赛者程序正确性的基础,确保他们的解决方案在不同情况下都能得到预期的结果。下面我们将深入探讨这个压缩包中...
每套模拟试题都包含若干个编程题目,可能涵盖的数据结构包括数组、链表、栈、队列、树、图等;算法方面可能涉及排序、搜索、动态规划、贪心、回溯等。此外,题目可能还会涉及到数学逻辑、概率计算、字符串处理等方面...
5. **测试计划与报告**:规划测试策略,如单元测试、集成测试、系统测试、验收测试等,记录测试结果,确保产品质量。 6. **操作手册和用户指南**:向最终用户提供软件的使用方法和常见问题解答,提升用户体验。 7....
2012-06-11 21:35 50,176 关于c语言和汇编语言相互嵌套调用的学习总结.doc 2012-06-11 21:11 190,993 典型算法包.rar 2012-06-11 21:16 264,555 内存管理和设备调试中文.pdf 2012-06-11 21:30 267,989 冈萨雷斯数字...
- 商不变性质的应用,让学生掌握被除数扩大若干倍,商也相应扩大相同倍数的规律。 2. **判断题**: - 考查了除法的余数性质,如76÷8和76÷9的区别。 - 了解除数、商和余数的关系,找出最大的被除数。 - 0除以...
ISO 7864是关于无菌一次性皮下注射针的国际标准,第四版于2016年8月1日发布。其目的是为制造商、监管机构以及医疗保健提供者提供一套统一的标准,以确保这些注射针在单次使用后能被安全地丢弃,避免交叉感染的风险...
二、误区二:对介电常数与材料选择的误解 高速PCB设计中,介电常数的选择对于信号的传输速度和质量有着直接影响。错误的介电常数选择将导致阻抗失配和信号反射,进而增加EMI问题。 对策分析: 设计师需要了解不同...
9. 测试计划:规划软件测试的策略和方法。 10. 修订历史:记录文档的修改和更新情况。 以上就是关于“软件设计文档标准(需求分析、概要设计等)”的主要内容,这个文档模板将指导开发者高效地完成这两阶段的工作,...
每份文档都有其特定的目标和格式,理解和使用这些模板可以帮助软件工程师提高效率,减少误解,并为项目成功提供有力保障。此外,良好的文档编写能力也是软件工程师职业素养的重要体现,对于个人职业发展有着积极的...