【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

编写良好的单元测试

  • 2017-02-03
  • 本文字数:3331 字

    阅读完需:约 11 分钟

尽量保持较小的单元测试规模,使用恰当的工具,将程序员和测试人员配对;这是编写良好的单元测试的一些建议。单元测试混合了编程和测试;程序员和测试人员要一起工作,互相学习,拓展自己的知识面。

Adrian Bolboacă是 Mozaic Works 的组织和技术教练 & 培训师。在 2017 欧洲测试大会上,他介绍了不同类型的自动化测试。InfoQ 将以 Q&A、综述和文章的形式对此次大会进行追踪报道:

[欧洲测试大会] 是让专家和实践者聚在一起,交流、学习和实践软件测试艺术。我们正在研究先进的新方法,以便让我们的测试更有效,加深对基本方法的理解,培养更强大的社区。

在博文“自动化测试目的”中,Bolboacă指出,单元测试应该完成如下工作:

单元测试关注一个方法或一个类。它应该非常小,最多只有几行代码。人们在编写单元测试时会犯许多错误,所以这不是小事。因为它们非常小,所以它们应该在内存中运行,而且,一个单元测试应该在几毫秒内运行完成。任何用到外部依赖(数据库、WebService、文件系统、I/O)的测试都不是一个单元测试,那是其他的东西(“集成测试(integration test)”、“综合测试(integrated test)”、验收测试、端到端测试,等等)。

InfoQ 就编写良好的单元测试及在单元测试中利用自动化采访了 Bolboacă。

InfoQ:谁编写单元测试重要吗?是开发人员,还是测试人员?

Adrian Bolboacă:单元测试更偏技术,它们通常关注代码细节,甚或是编程语言特有的概念。在类似 Java 这样的静态编程语言和类似 Ruby 这样的动态编程语言中,单元测试看上去是不一样的。这就是为什么编写单元测试主要应该由程序员负责。

另一方面,测试人员更了解如何制定测试计划,根据特定分析,如等价类划分和边界值分析,定义有价值的值。因此,程序员需要从测试人员那里“窃取”这类知识,或者,他们可以和测试人员结对,一起讨论需要编写的测试,但是,之后应该由程序员实现它们。

根据我的经验,结对是最好的选择,因为测试人员和程序员可以更好地互相学习,拓展自己的知识面。

InfoQ:什么时候应该编写单元测试?

Bolboacă:团队可以在生产代码编写完成之后编写单元测试。我们称之为“测试延后(test after)”。但是那通常很困难,因为在编写生产代码时需要时刻考虑可测试性。如果我们选择了这种方法,则生产代码需要经过一个代码审核流程,以确保它是可测试的。只有在完成这项工作之后,程序员和测试人员才可以继续结对创建测试。

也有一种方法是“测试优先(test-first)”,我建议从同伴那里“窃取”了大量测试知识的程序员使用这种方法。使用这种方法时,我们先分析问题,然后编写一个单元测试,最简单的实现代码,一个单元测试,实现它,依此类推。当团队达到了这个水平,我会说,编写单元测试的程序员是半个测试人员了,因为“测试优先”方法需要大量的测试知识。在这种情况下,测试人员最终将专注于审核单元测试及编写验收测试。

在采访“测试优先方法”中,Gil Zilberfeld 谈了测试优先方法所带来的好处:

测试优先方法定义了需要做什么。它定义了我们为解决特定问题而需要编写的代码,因为我们有一个测试形式的定义。只要运行测试,我们就很容易知道我们的功能是否有效。

采用这种方法可以获得更高的覆盖率,因为测试成了一等开发活动,而不是拖到最后。

此外,在编写这些测试并详细说明场景时,我们更深入地了解了问题空间,因为许多问题会被提出来。在测试延后方法中,这些讨论有时候都不会发生,开发人员按照自己的想法编写代码,而不是根据解决方案的需要。

在文章“ QA 部门消亡日”中,Eli Lopian 解释了单元测试为什么可能成为 QA 杀手:

单元测试是一种测试特定代码片段的方法,它可以确保该代码段可以正常运行并且契合软件拼图。有证据表明,借助单元测试,你可以检查超过 90% 的代码,而且,和 QA 的手动测试工具不同,恰当构建、可以自动测试的单元测试可以随着代码库一起演化,实时测试代码。

InfoQ:您在单元测试中如何利用自动化?

Bolboacă:单元测试是一个分析过程,会产生一份测试计划,然后测试计划会被自动化。

为了实现这些测试的自动化,请记住以下几个要点:

  1. 使用领域语言命名测试名称
    通常,我们就只管编写测试。但是,读代码的次数要多于写代码。因此,要善待你的同事和未来的自己,清晰地命名测试。使用领域名称,而不是技术名称。类似“ExceptionOnOverflow”、“TestThree”和“CustomerTest”这样的名称并不清晰。取而代之,我们应该使用类似“WhenTooManyPlayersAreAddedAnErrorIsReturned”、“ACustomerNeedsAllFieldsValidated”、“ValidCustomerCanBeUsedByOrder”和“InvalidCustomerIsRejectedByOrder”这样的名称。这样,所有了解业务领域的人都会清楚你那里在测试什么,甚至是你的客户。
  2. 编写短测试
    单元测试要短而清晰,并且只有一个目的。最好的测试有 3 到 4 行代码,那样,对任何阅读测试代码的人而言都会非常清晰。我们需要有许多类似这样的小的单元测试,它们一起构成了产品的免疫系统,其中每个测试都像是一个免疫细胞。如果出现了 Bug,则会有一个小测试准确地告诉你问题在哪里。这样,你就会得到迅速的反馈和一个简单的开发测试周期。
  3. 每个测试一个断言
    如果你在一个测试中包含了不只一个断言,则你的测试目的就不只一个。在这种情况下,测试名称变得奇怪不清晰,测试变得太长,反馈也变得不清晰;你永远无法知道哪个断言通过了,哪个断言失败了。假如你依次有三个断言。如果第一个断言失败了,则后面两个永远都不会检查。如果你修改了一些生产代码,那么当代码变化时,后面两个断言就无法发挥作用了。在这种情况下,你就会错误地认为自己的代码有安全保障和回归测试。
  4. 不要链接测试
    我经常看到人们有链接测试的习惯。这通常是因为准备工作非常困难。但这不是一个解决方案。在测试链中,依赖于其他测试的测试之所以失败,大多数情况下都是因为前面的测试失败了。在这种情况下,你可能会修改代码让测试通过,但你可能会因为测试不完备而引入没有验证到的缺陷。测试应该总是相互独立,就像免疫系统里的免疫细胞那样。它们都依赖于产品,而不是互相依赖。
  5. 使用恰当的工具
    测试工具有许多:测试框架、模拟框架、测试执行器、性能测试工具、安全测试工具,等等。你要确保选择了适合工作任务的工具。不要仅仅只是使用你知道的工具。通常,xUnit 框架非常适合于大多数的自动化测试类型,但性能测试和安全测试要使用专门的工具。如果你希望让良好的测试成为可执行的规范,那么你也可以使用 xUnit,但是,你也可以使用一些 BDD 框架来简化测试工作。请记住,从中长期来看,选择一款测试框架是你必须作出的决策。要考虑学习成本以及使用和维护成本。

由于当前市场对特性的交付速度要求越来越高,我们需要用一种巧妙的方式自动化产品验证过程。这就是为什么自动化如今是必不可少的。

InfoQ:对于编写良好的单元测试,您有什么建议吗?

Bolboacă:单元测试源于工业生产,大多数人都忘记了这一点。在工业上,我们需要测试每一个小部件,看它的质量是否合格,我们是否可以把它用在下一步的部件装配中。在软件行业,我们没有这样清晰的单元定义;人们有不同的看法——方法、类、模块。第一个难点是让所有的团队成员对单元是什么有一个共识,并编写相应的测试。在我看来,单元非常小,就像发动机中的螺丝或者家具中的钉子那么大。所以,我建议定义单元是什么,并在测试审核阶段对此进行密切关注,确保其得到了执行。

单元测试混合了编程和测试。为了编写简单、快捷、可维护的测试,程序员需要知道许多测试概念。我对程序员的建议是从负责测试的同事那里学习一些基本的概念:等价划分、边界值分析、测试覆盖、正向测试、逆向测试。

关于单元测试,还有另外一个经常被遗忘的部分,那就是分析。我们不能不经过思考就立即开始编写测试。我们需要分析问题,如果可能对它进行划分,然后再考虑我们需要编写的单元测试。这里有一个不错的建议,就是总是从系统输出开始,然后找出生成那个输出的可能输入。感谢 Chris Matts 把这个技巧教给了我。

在编写单元测试时,我们应该使用来自问题领域的词汇。测试应该体现一项特性存在于产品中的理由。一个了解业务领域但不了解编程的人也应该能够阅读你的测试。在那方面,和分析师结对非常有用。

查看英文原文 Writing Good Unit Tests

2017-02-03 18:006474
用户头像

发布了 1008 篇内容, 共 374.9 次阅读, 收获喜欢 341 次。

关注

评论

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

AI自动生成代码,是时候冷静下来思考如何保障代码安全了

华为云PaaS服务小智

云计算 华为云 代码检查 华为开发者大会 AI编程

敏捷在医疗器械开发中的应用 —— Q&A

ShineScrum捷行

毕业季 | 程序员初入职场必备软件开发神器

华为云开发者联盟

云计算 软件开发 华为云 华为云开发者联盟 企业号 6 月 PK 榜

高并发场景下,6种解决SimpleDateFormat类的线程安全问题方法

华为云开发者联盟

开发 华为云 华为云开发者联盟 企业号 6 月 PK 榜

【6.23-6.30】写作社区优秀技术博文一览

InfoQ写作社区官方

热门活动 优质创作周报

强化学习从基础到进阶-案例与实践[5.1]:Policy Gradient策略梯度-Cart pole游戏展示

汀丶人工智能

人工智能 深度学习 强化学习 策略梯度

2023-06-30:给你一个 rows * cols 大小的矩形披萨和一个整数 k, 矩形包含两种字符: ‘A‘ (表示苹果)和 ‘.‘ (表示空白格子), 你需要切披萨 k-1 次,得到 k 块披

福大大架构师每日一题

Go 算法 rust Go 语言 福大大架构师每日一题

远程desk工具利用总结

快乐非自愿限量之名

远程 ToDesk

专访|严靖炜:从参与 MatrixOne 到论文入选 IEEE BMSB 2023

MatrixOrigin

数据库 云原生 超融合

🔥🔥🔥我可算把【年中复盘】玩明白了

禅道项目管理

总结 复盘

企业号 7 月 PK 榜,火热开启!

InfoQ写作社区官方

热门活动 企业号 7 月 PK 榜

在找稳定的企业级数据云平台?奇点云DataSimba R4.9 LTS发布

奇点云

产品升级 奇点云 数据基础设施 DataSimba

打造数智物流底座,华为云DTSE助力物联云仓解锁物流新“速度”

华为云开发者联盟

云计算 华为云 华为云开发者联盟 企业号 6 月 PK 榜

金域医学2023“域见杯”医检人工智能开发者大赛正式启动

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 6 月 PK 榜

强化学习从基础到进阶-案例与实践[4.2]:深度Q网络DQN-Cart pole游戏展示

汀丶人工智能

人工智能 深度学习 强化学习 DQN

解放开发者——5个好用的低代码开发平台

树上有只程序猿

人脸识别技术在智能家居中的应用

来自四九城儿

使用 diffusers 训练你自己的 ControlNet 🧨

互联网工科生

controlnet

Java 网络编程 —— 客户端协议处理框架

快乐非自愿限量之名

Java url

强化学习从基础到进阶–案例与实践[11]:AlphaStar论文解读、监督学习、强化学习、模仿学习、多智能体学习、消融实验

汀丶人工智能

人工智能 深度学习 强化学习 7月日更

SQL 优化(三):使用覆盖索引

hungxy

全面解析 | 大模型时代如何利用弹性计算服务应对大算力挑战

阿里云弹性计算

云计算 弹性计算 AIGC

低代码平台源代码对程序有哪些作用?

这我可不懂

低代码 源代码 JNPF

什么是MES?国内做MES系统的企业哪家好?

优秀

MES系统 mes

迄今为止最完整的DDD实践

阿里技术

架构 DDD

人脸识别技术在社交媒体中的应用

来自四九城儿

神级程序员,都在用哪些生产力工具?

互联网工科生

程序员 工具 生产力

万木健康:用AIGC创造医生的第25个小时|TE洞察

TE智库

人工智能 AIGC 医疗健康

基木鱼平台全链路升维,商家经营迎来AIGC生意经

Geek_2d6073

编写良好的单元测试_语言 & 开发_Ben Linders_InfoQ精选文章