AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

编写良好的单元测试

  • 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:006986
用户头像

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

关注

评论

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

传统企业在进行信息化升级的过程中,如何做好信息化顶层设计

BeeWorks

搭建在线帮助中心,轻松帮助客户解决问题

小炮

【6.3-6.10】精彩博文回顾

InfoQ写作社区官方

优质创作周报

自助洗车加盟前要准备些什么吗

共享电单车厂家

自助洗车加盟 自助洗车品牌

新思科技助力以色列Visuality Systems推进安全“左移”

InfoQ_434670063458

软件开发 代码 新思科技 安全测试 安全左移

flutter系列之:UI layout简介

程序那些事

flutter 程序那些事 6月月更

2022 年 DevOps 路线图|Medium

观测云

APICloud 5月SDK发版说明

YonBuilder低代码开发平台

App 低代码 APICloud 可视化开发

首批!青藤通过信通院CWPP能力评估检验

青藤云安全

网络安全 主机安全 信通院

新思科技在《 2022 年 Gartner® 应用安全测试关键能力报告》中表现优异 在五个常见用例中荣获最高分

InfoQ_434670063458

新思科技 Gartner 应用安全测试

李飞飞:我更像物理学界的科学家,而不是工程师|深度学习崛起十年

OneFlow

人工智能 深度学习 李飞飞 ImageNet

攻防演练 | 网络安全“吹哨人”:安全监控

青藤云安全

网络安全 主机安全 攻防演练

数据的软删除—什么时候需要?又如何去实现?

Geek_rze78a

6月月更

华为云鲲鹏DevKit代码迁移实战

乌龟哥哥

6月月更

APICloud可视化开发丨一键生成专业级源码

YonBuilder低代码开发平台

App 低代码 可视化 APICloud 移动端开发

Linux 之父亮相,OpenCloudOS 社区开放日来了

腾讯安全云鼎实验室

APICloud可视化开发新手图文教程

YonBuilder低代码开发平台

App APICloud 低代码开发 移动端开发 可视化开发

项目那么多为何要选择自助洗车

共享电单车厂家

自助洗车加盟

想加盟自助洗车不知道一般啥流程

共享电单车厂家

自助洗车加盟

为什么要开发分布式操作系统

LAXCUS分布式操作系统

分布式计算 分布式存储 超算 云边端协同 分布式操作

ServerLess Aws Lambda攻击与横向方法研究

火线安全

云安全

图像搜索是什么

Geek_e369a5

图像搜索 图像搜索是什么

第二届征文大赛开奖啦!速来领奖!

InfoQ写作社区官方

热门活动 初夏征文

Flutter在数字生活的发展与天翼云盘落地实践

flutter 架构 混合应用开发 移动开发 客户端

推开混合云市场大门,Lenovo xCloud的破局之道

脑极体

自助洗车加盟具体都有哪些优势

共享电单车厂家

自助洗车加盟

仅需三步学会使用低代码ThingJS与森数据DIX数据对接

ThingJS数字孪生引擎

可视化 数字孪生

掌握高性能计算前,我们先了解一下它的历史

华为云开发者联盟

华为云 高性能计算 处理器

一文带你了解J.U.C的FutureTask、Fork/Join框架和BlockingQueue

华为云开发者联盟

Java 开发 华为云

改变世界的开发者丨玩转“俄罗斯方块”的瑶光少年

华为云开发者联盟

人工智能 华为云 俄罗斯方块

Spark ShuffleManager

Geek_qsftko

大数据 spark

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