写点什么

关于测试的若干误解

  • 2011-07-07
  • 本文字数:3165 字

    阅读完需:约 10 分钟

本文中所表达的观点仅代表 Liam O’Connor 个人意见,与其雇主(NICTA)无关。

如果说你我之间有什么相似之处的话,那就是你可能阅读过大量文章,在其中作者主张测试驱动开发(TDD,Test-Driven Development)或者其他涵盖了广泛测试(无论是单元测试还是集成测试层面上)的开发实践。我认为,关于这些实践的许多主张缺乏实际项目经验,很难让人相信他们的观点。事实上,当我们把这些非常严格的测试实践应用于大型项目上时,通常它们根本无法顺利工作。

在本文中,我将说明一些关于测试的常见误解。我希望,如果你在编写测试时也存在这样的误解,那么本文能帮助你和你的团队来判断何时适合测试,何时不适合测试。

误解一:测试可以表明我的代码是正确的!

虽然这种误解在直觉上是正确的,但是你确实无法依赖测试来建立任何形式的具有严格正确性的标准。每当你编写了一个测试,你就已经测试了程序中的一种可能情况。当程序中存在许多单元时,或许存在无限多种(或是多得难以应付的)可能的情况需要测试时,那么测试所有可能情况是不可行的——因此,典型的对策是测试一些出错情况、边界情况以及若干恰好确保一切正常的“常规”情况。

如果你的目标是正确性,那么上面谈到内容还远不足以满足要求。尽管程序仍存在许多 bug,但是开发一套总是可以通过的测试还是相当容易的。然而有些 bug 根本不可能通过测试检查出来——其中竞争条件和包括并发性在内的其他错误都是经典的例证,即使你已经对调度程序进行控制,然而可能的交错操作的数量增长是如此之快,以至于可靠地测试很快成为了不可能完成的任务。

因此,测试无法展示所有情况下的正确性,除非是在最普通的情况下,那样我们可以在测试中完全指定程序单元的行为。对于这些普通情况,往往不值得从一开始就编写测试;之所以说这些情况实在是太普通了,是因为我们所要测试的代码本身就是微不足道的!通过为那些微不足道的代码片段编写测试只完成了一件事,那就是增加维护开销,并且为测试机增加工作量。

既然测试也只是一些代码,那么在你的测试中同样可能存在 bug。如果编写测试与编写代码的是同一个人,那么他们往往可能错误地实现一个程序单元,然后编写一个确保那个错误行为能够通过的测试。此问题的根源在于开发者误解了规格说明,而不是实现过程中犯下的小错误。

如果你确实需要保证正确性,那么请对你的代码进行形式化验证(目前的验证工具要比过去好得多)。如果你不需要保证正确性,那么编写测试就可以了。须牢记,编写测试的作用就如同烟雾报警器对于火灾的作用一样,其实它并不能检测出各种各样的问题。

误解二:测试是可执行的规格说明!

基于以下几个原因我认为这个观点是错误的。先来看看在我的字典里 _ 规格说明 _ 的定义:

一组需求,用于界定对于某一对象或过程的准确描述。

因此,如果我的代码符合规格说明的要求,那么它就应该是完全正确的,因为规格说明准确界定了代码的行为。如果说我的测试是规格说明,那么必须进而证明测试的正确性。正如我们已经讨论过的,测试并没有做这样的事情,因此测试不是规格说明。

让我们看下实际情况,假设一名开发者通过阅读测试用例可以推断出某个函数的预期行为,然后引入一大堆含混不清的测试用例;如果测试用例不够全面,那么我们可能最终推断出错误的结论,有时可能与预期行为仅有细微差别。

此外,对于测试用例并未进行一致性检查。也就是说,由于开发者失误或误解,因此你的测试可能实际“指定”了一个非预期的行为。这可能会导致在你的测试中出现一些矛盾,因此也可以说你的规格说明中出现了矛盾。

随机测试软件,例如 QuickCheck ,会让编写测试的工作变得非常简单,就像本应包含的布尔属性一样,而且该软件会为你生成测试用例。该软件使得测试更接近于可执行的规格说明,不过它仍然不会对属性进行一致性检查。

误解三:测试会让我们拥有良好的设计!

当让一个糟糕的设计可以测试时,此设计仍然具有改进的可能,因此测试不是优良设计实践的替代品。当为系统接口编写大量的测试时,实际上是增加了开发者投入在那些接口上的“工作投资”。当这些接口不再是最佳选择时问题就会随之产生,即开发者已经为那些接口编写了大量测试。改变接口也就意味着改变所有与之配套的测试。由于测试与那些接口紧密耦合在一起,因此其中大多数测试将必须被废弃并重写。既然大多数开发者的成长依附于他们所从事的工作,这会导致在项目的生命周期中对于那些次优的设计决策踌躇不前,尽管那些决策不是最适合的。

在这里给出的解决方案是,只有在你编写了一系列原型之后再开始着手测试。这样你就不必为测试那些可能在稍后会被大量重构的代码而焦虑。对于开发者和测试机而言,所做的一切都是在增加工作量,而且当需求或接口改变时,开发者必须销毁数小时的工作成果,这会使他们更心痛。而如果你不等待而进行了测试,那么你的测试实际上会导致 _ 糟糕的设计 _,因为开发者将不愿进行任何重大的重构。

此外,让代码可以测试很 _ 困难 _。通常人们仅仅为了让测试更加容易而采用有问题的设计决策;尝试大量模拟接口实现,或者是编写具有大量 _ 代码 _ 的测试用例,以至于测试用例代码本身几乎也需要测试,这些做法都暴露出对于抽象的泄漏(mock 对象和 stub 往往会经受此问题的折磨)。

误解四:测试会让更改代码更容易!

测试并不 _ 总是 _ 让更改代码更容易,然而,如果你正在对底层接口实现进行修改,那么测试可以帮助你捕获新实现中的功能衰退或非预期的行为。如果你正在对程序的更高层次结构进行修改,然而这种对立的情况则是更普遍的现象。测试通常与更高层次接口紧密耦合。改变这些接口就意味着重写测试。在那种情况下,你让自己活得很辛苦——你将必须重写那些测试,从而给自己增加了更多的工作,而且之前的旧测试对于确保你没有引入功能衰退而言无能为力,这意味着测试根本帮不上忙。

所以,不写测试?

我没有说你不应该编写测试。对于提高信心以及阻止软件功能衰退而言,测试是一种有价值的方式。然而,测试无法统一带来优良的设计、正确性、技术规格说明或者轻松地重构,至于原因如上所述。过度使用测试会让开发变得 * 更难 * 而不是更容易。

同样,根本不验证代码会让质量保证无从谈起,不过会让快速构建原型更轻松。测试在质量保证与灵活性之间引入了一个权衡问题,所以我们必须在二者之间做出适当的妥协。

关于作者

Liam O’Connor曾任职于 Google,并任教于新南威尔士大学。最近,他开始为 NICTA l4.verified 项目工作,此项目是对操作系统内核进行形式化验证,NICTA 是澳大利亚领先的 ICT(Information and Communications Technology,信息与通讯技术)研究机构。

查看英文原文: Testing Misconceptions

译者评论

俗话说“尺有所短寸有所长”,此话与“No silver bullet”有异曲同工之妙。既然世间没有包治百病的灵丹妙药,那么就应对症下药,而且下药前最好弄明白药品的功效及禁忌,否则吃错药的后果不堪设想。

言归正传,测试的“功效”不可否定,但对其“禁忌”的说明却没有那么清晰。本文作者提出了几点对于测试“禁忌”的看法,或许个别观点有失偏颇,但是其目的是希望大家可以“更加客观、全面地认识 TDD 及测试”。

下面收集了几个与 TDD 及测试有关的链接供大家阅读。

相关阅读


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011-07-07 00:003663
用户头像

发布了 55 篇内容, 共 18.9 次阅读, 收获喜欢 1 次。

关注

评论

发布
暂无评论
发现更多内容

一站式统一返回值封装、异常处理、异常错误码解决方案—最强的Sping Boot接口优雅响应处理器

京东科技开发者

独家揭秘丨GreatSQL 的MDL锁策略升级对执行的影响

GreatSQL

华为云CodeArts API:API管理一体化平台 7月新特性介绍

华为云PaaS服务小智

API 华为云

Flutter开发组合思路(小程序+App)

Geek_2305a8

亚马逊云科技服务之安全巡检及优化

伊克罗德信息科技

如何选择合适的代理IP?

IPIDEA全球HTTP

【原创】【深入浅出系列】之代码可读性

京东科技开发者

数据库运维实操优质文章分享(含Oracle、MySQL等) | 2024年7月刊

墨天轮

MySQL 数据库 oracle sql postgresql

政策红利叠加技术支持:低门槛开发高潜力游戏直播平台

软件开发-梦幻运营部

ByteHouse案例实践:某平台如何基于OLAP大幅提升复杂查询效率?

字节跳动数据平台

数据库 大数据 云原生 Clickhouse 数仓

碳课堂|数字技术如何助力碳中和目标实现?

AMT企源

数字化转型 碳中和 碳达峰 碳管理

岳阳东宇第六家高端网咖开业,这位老板笃定14900K的原因是?

E科讯

StarRocks 存算分离 Compaction 原理

Ding_Kai

数据仓库 StarRocks

QPS提升10倍的sql优化

京东科技开发者

IPQ5010 IPQ5018 WiFi 6 TRIBAND Routerboard | Industrial-Grade DR5018S

wallyslilly

ipq5018 IPQ5010

SOL项目开发代币DApp的基本要求、模式创建与海外宣发策略

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

小度联合新华网客户端,举办“AI技术对中小学教育的深度赋能”主题活动

科技热闻

解析淘宝商品评论API返回值中的用户信息与行为

技术冰糖葫芦

API Explorer API 接口 API 测试 API 策略 pinduoduo API

上海锐起科技桌面虚拟化方案与中国芯的不解情缘

上海锐起科技

什么是BPM,如何构建一个BPM App?

NocoBase

低代码 BPM 无代码

链动2+1系统开发升级版/规则玩法/案例设计/项目逻辑/源码功能

V\TG【ch3nguang】

沪港数据竞赛圆满落幕,启信宝独揽双重大奖

合合技术团队

科技 合合信息 启信宝

一直没找到合适的开源富文本?何不尝试下Fluent Editor,一个基于Quill 2.0的富文本编辑器,功能强大、开箱即用!

OpenTiny社区

前端 OpenTiny TinyVue 开源组件库

KubeCon China 2024 现场见!与华为云原生专家畅聊服务治理,一起Meet The Authors !

华为云原生团队

云计算 容器 云原生 KubeCON

YRCloudFile V6.13.0 发布| 新增弹性数据网络(Elastic Data Network)功能

焱融科技

加密市场的挑战与机遇:周期性变化与未来叙事趋势

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

云解析的宕机切换是什么意思?有什么用?

国科云

极客天成和ScaleFlux完成产品相互兼容认证

ScaleFlux

分布式存储 企业级SSD

AI制作PPT软件有哪些?这款中文版Gamma值得推荐!

职场工具箱

效率工具 职场 PPT 办公软件 AI生成PPT

1场Keynote,7场技术演讲 | Karmada云原生多云容器编排引擎闪耀亮相 KubeCon China 2024

华为云原生团队

云计算 容器 云原生 KubeCON

MES系统在铜加工行业的应用

万界星空科技

mes 万界星空科技 铜业 制造业工厂 铜加工

关于测试的若干误解_研发效能_Liam O'Connor_InfoQ精选文章