专注测试技术的课程订阅站点

Long Live the Test Pyramid

最近看到一篇关于测试金字塔的讨论,觉得非常有道理,原文在这里: https://www.smashingmagazine.com/2023/09/long-live-test-pyramid/

顺便翻译一下,希望对大家有所帮助。

我亲爱的同事 Jan Philip Pietrczyk 曾经对开发者在编写功能代码方面的责任发表过评论:

“我们的日常工作最终会交到信任我们的人手中,他们不仅信任我们已经尽力而为,还信任我们的代码能够正常运行。” — Jan Philip Pietrczyk

他的这些话一直深深地印在了我的脑海中,因为它让我们的代码置于依赖它的人们的背景之中。在这个快节奏的世界里,用户信任我们编写最优秀的代码,并且我们的软件“简单地”可以运行。确实,要达到这种信任水平是一个挑战,这就是为什么测试是任何开发堆栈中如此重要的一部分。测试过程评估了我们工作的质量,通过对不同情况进行验证,帮助在问题变得严重之前识别问题。

测试金字塔是众多测试策略之一。尽管自 2012 年引入以来,它可能已经成为了主要的测试模型,在过去的十年中占据主导地位,但我发现现在提及它的次数并不像过去那么多。它是否仍然是测试的“首选”方法?与此同时,许多其他方法也已经涌现,因此是否可能是测试金字塔被更适合当今开发的更现代模型所淹没和遮盖?

这就是我想要探讨的问题。

测试策略的关键点

与用户建立信任需要一个强大的测试策略,以确保我们编写的代码使产品按照他们的期望工作。我们应该从哪里开始编写好的测试?我们需要多少个测试?许多人一直在思考这个问题。但是 Kent C. Dodds 发表的一个简短评论让我恍然大悟。

“最大的挑战是知道要测试什么,以及如何进行测试,以获得真正的信心,而不是测试实现细节所带来的虚假信心。”

-Kent C. Dodds 这就是起点!确定测试的目标是测试策略中最关键的任务。互联网上充斥着描绘糟糕决策的迷因,其中许多是因为根本不知道特定测试的目的以及我们需要多少测试来确保信心。在测试方面,有一个“正确的比例”,以确保代码经过适当的测试并且按照预期工作。

问题在于许多开发人员只关注一种类型的测试 - 通常是单元测试覆盖率 - 而不是对各种单元如何协同工作制定策略。例如,当测试一个水槽时,我们可以分别测试水龙头和下水道,但它们是否协同工作呢?如果下水道堵塞,而水龙头继续放水,那么事情就不正常了,即使单元测试表明水龙头正常工作。

关于测试的方法通常用不同的形状来描述,就像我们已经看到金字塔模型一样。在这篇文章中,我想分享一些我观察到的形状,以及它们在现实场景中的应用,最后总结出哪种测试策略符合我对当今开发实践中良好测试覆盖的个人标准。

回顾基础知识

在此之前,让我们回顾一些不同测试类型的常见定义,以刷新我们的记忆:

手动测试

这是由实际人员执行的测试。这意味着测试将要求真实用户按照脚本化的使用案例进行点击应用程序,以及未经脚本化的尝试在不可预见的情况下“破坏”应用程序。这通常是通过与由产品团队观察的用户进行面对面或远程面试来完成的。

单元测试

这种类型的测试是将应用程序分解为小的、隔离的、可测试的部分,或者称为“单元”,通过分别和独立地测试每个单元以确保其正常运行来提供覆盖。

集成测试

这些测试关注组件或系统之间的交互。它们一起观察单元测试,以检查它们在集成在一起作为整体工作时是否良好。

端到端(E2E)测试

在这种类型的测试中,计算机模拟实际用户的交互。将 E2E 视为验证用户故事的一种方式:用户是否可以完成需要一系列步骤的特定任务,结果是否符合预期?这是从用户体验的一端到另一端进行测试,确保输入产生正确的输出。

那么,这些测试类型应该如何互相交互呢?测试金字塔是我们传统依赖的隐喻,用来将这些不同类型的测试整合到一个完整的测试套件中,适用于任何应用程序。

伟大的测试金字塔

测试金字塔是由 Mike Cohn 在他的书《成功的敏捷》中首次引入,并由 Martin Fowler 在他的“实用测试金字塔”文章中进一步发展的,根据测试的性能和成本对测试进行了优先排序。它建议编写具有不同粒度级别的测试,包括较少的高级别测试以及更多快速、经济、可靠的单元测试。推荐的测试顺序是从快速和经济到慢和昂贵,从底部开始有很多单元测试,然后是服务,即中间的集成测试。然后是位于顶部的较少但更具体的 UI 测试,包括端到端测试。

https://files.smashing.media/articles/long-live-test-pyramid/test-pyramid.jpg

微软的office365给软件测试带来的变革

微软今天发布了集成了 GPT-4 模型的 office 套件,从演示视频看,大概可以做这样一些事情

  • 输入指令自动做表
  • 输入指令写邮件
  • 输入指定自动做 ppt,而且一做就是好多页,挺震撼的

稍微了解了一下原理,大概流程是

  • 用户发送 prompt 到 office
  • office 获得用户授权访问用户的核心数据(email,聊天记录,会议信息,日程,联系人列表等)
  • office 整合用户信息修改 prompt
  • office 将修改后的 prompt 发送到语言模型
  • office 拿到语言模型的返回,并结合用户数据进行信息整合
  • office 拿到整合后的信息和 app 的命令列表,进行自动化和信息展示

从原理可以看出 office 基本上把语言模型,目前也就是 GPT-4 当成了黑盒,这样应用软件层面其实不需要了解太多模型的细节和实现,只需要把模型当成语言理解器,内容生成器就好了。语言模型只负责理解用户的 prompt 和生成内容,office 负责整合数据,调整 prompt,以及我们今天讨论的话题,执行 ui 自动化。

未来办公软件的形态

未来办公软件有很大概率会跟 AI 结合起来,他们大概会是

  • 有自己的主要形态和业务领域,比如邮件客户端,文字处理软件客户端,也就是有 UI,有交互,有一些逻辑,跟现在的办公软件差不多
  • 有 AI 辅助的能力,可以接受用户的 prompt 并进行修改和吟唱,然后调用大语言模型
  • 有完善的 UI 自动化能力,根据大语言模型返回的内容自动化的进行操作,并展现给用户

所以简单来说,未来的办公软件将会调用 AI,并执行自动化。

那么未来的软件都会有 ui 自动化的接口

这个结论是水到渠成了,有 ui 自动化接口,那么就需要做 ui 自动化测试。所以对于一些泛化的办公软件开发团队来说,测试人员不仅要负责传统的功能测试,还需要调用 ui 自动化接口,保证接口的正确性,甚至是 ui 自动化的测试代码都可以成为大语言模型的无监督学习物料。

更泛化的办公软件实现

也许未来会出现更加泛化办公软件或者是办公流程软件,可能包含这些部分

Whatsup是怎么做测试的

看到了一篇关于 whatsup 是如何做测试的文章,尽管里面有一些拍领导彩虹屁的嫌疑,不过还是可以让我们了解到 meta(whatsup 属于 meta)内部整体质量保障架构的情况。翻译了一下,供大家参考。原文地址: https://automationhacks.io/2023-10-18-how-whatsapp-tests-software

我正在思考 WhatsApp 团队如何测试其应用程序以及全球其他团队可以从他们的测试工程实践中学到什么。这也是很多人问我的一个经常性问题,所以让我们来揭开一些面纱,好吗?

测试方法

我在 2021 年底到 2023 年中期的一年半时间里,作为 WhatsApp 测试自动化团队的成员,在他们伦敦办公室工作,我有幸近距离观察了一个拥有 20 亿多用户的应用程序是如何进行测试的。

WhatsApp 测试自动化团队负责开发测试基础设施、工具和框架,以便让开发人员为 WhatsApp 客户端(尤其是 Android、iOS、Web 和桌面应用程序)编写高效的测试。这是整个组织测试策略的关键部分。

在某些方面,这些方法与其他面向消费者的移动应用程序相似,具有测试金字塔的各个典型层次。WhatsApp 团队倾向于使用许多开源工具来编写自动化测试,但也使用许多内部元工具和基础设施来加强整个测试策略。WA 的测试方法也与元应用程序有很大的不同。

在本文中,我将讨论两个关键因素,这些因素促成了自动化的强大文化。

  • 框架和基础设施
  • 支持这一文化的团队和角色

让我们深入探讨一下吧 🏊

测试框架

首先,让我们看看测试金字塔的不同层次,以及使用了哪些不同的工具和框架。

对于移动框架,自动化测试在测试金字塔的各个层次上进行编写,使用了大量的 Espresso 和 XCUITests,相对较少的 E2E 测试。

Android

  • Unit tests: JUnit, Roboelectric
  • UI tests: Espresso
  • Screenshot tests: Screenshot tests for Android (read more about this here 🔗)
  • E2E tests: Jest-based internal E2E testing framework

iOS

可靠的预发布环境(staging环境)对测试的重要性

很少看到有人讨论预发布环境的问题。今天正好看到一篇文章The Importance Of Testing In A Reliable Staging Environment,里面提到了一个很有意思概念反质量文化。个人认为文中讨论的预发布环境可能更接近于国内认知中的测试环境和预发布环境的结合体。尽管如此,文章还是非常有借鉴意义的,随便用 ai 翻译了一下,供大家参考。

许多软件开发组织会选择容忍缺陷丛生的预发布环境:很少有人认为这是个大问题。如果你从事软件开发,那么你很可能见过类似普通人的第一辆车那样状态的预发布环境。我们大多数人承诺在最初买下车辆时会修复问题,但实际上车辆保持的状态跟买来时一模一样!车门镜碎了,尾灯闪烁不定,勉强还能开。我们说服自己这些小问题不重要,也太贵了不值得修复。

我想精确地解释为什么这些“小”问题会给你的工程团队带来重大问题。事实上,它们很可能已经造成麻烦了。然后,我将给你一些建议,如何说服你的公司投入一些资源从根本上解决这些问题。最后,我将为你提供一些想法,以确保你成功完成清理预发布环境的任务——并保持其清洁!

预发布环境:一些基本事实和现实

当我谈到“预发布环境”时,这意味着任何工程师被期望用来执行其日常职责的开发或测试环境。这包括开发新特性、回归测试、运行自动化测试等。你的公司可能使用不同的术语。

质量低下、不可靠的预发布环境以及对生产环境的糟糕复制会向你的软件开发生命周期中引入细微的缺陷。它们很可能会被你的开发团队遇到,可能有人会在回顾会上提出几次。但从未采取行动解决它们。你有更高的优先事项;也许知道如何解决问题的人不再为公司工作了。无论如何,总有某种原因导致现在无法处理它。毕竟,它并没有阻塞任何人。然后,使用预发布环境的这种环境缺陷就被接受为一个事实。

“嘿,伙计们,我注意到这个页面在我们的预发布环境中无法加载……但这在生产环境中却不会发生。我们知道这是为什么吗?🤔” “哦,天呐,它就是这样的 😂 别担心!” 这就是反质量文化开始渗入你的流程和团队心态的地方。

这将造成三个问题:

  • 反质量文化
  • 更高的生产问题风险
  • 你的开发流程中的隐藏成本

反质量文化

什么是反质量文化?

反质量文化是团队范围内对低质量工作方式的接受。

如果说质量文化是为了质量本身而努力,那么反质量文化就是其反面。你的团队会慢慢对预发布环境中的意外行为变得麻木。他们开始假定(或怀疑)所有出现的意外行为都是由于环境被忽略而不是真正的问题引起的。工程师已经习惯了看到这些问题,学会了规避它们,结果也更加疏忽大意。这是一种反质量文化,直接导致缺陷疲劳。当我们习惯看到缺陷时,缺陷疲劳就会发生,我们会 develop 认知偏见并认为不相关的缺陷是环境问题,并因此改变我们的行为,可能会带来负面结果。

在缺陷疲劳出现之前,优秀的工程师会勤奋地花时间调查这些问题。你可能会注意到这体现在团队聊天消息、会议投诉或回顾会议中的问题上。你的负责人或管理人员可能最初不认为它们足够重要到需要修复的程度。但不太明显的是,在团队将其归类为环境问题之前,调查这个问题所浪费的时间有多少。

考虑这些场景。它们现在可能正在你的工程部门发生:

  1. 一位工程师正在代码库的一个不熟悉的部分工作,当他们看到页面的一部分突然不像应该的那样加载时。他们想独立工作,并决定在麻烦别人之前自己调查这个问题。他们花了一个小时调试自己的代码,假定他们的更改导致了这个问题,然后代码突然又开始正常工作了。后来他们询问并发现这是一种他们不知道的间歇性问题。
  2. 一位工程师完成了一个变更的工作,在发送给 QA 之前,他们快速检查了这个分支。他们在这个领域很有经验,完全了解软件中的所有怪癖。他们注意到一些奇怪的 UI 缺陷,但很快就得出结论,不太可能是他们的更改导致的……因为环境一贯有缺陷。他们将任务发送给 QA,很快就被打回,因为 QA 确认这确实是一个真正的问题。

随着时间的推移,第一种情况下的工程师可能会厌倦调查这些环境缺陷,无论是有意识地还是无意识地。最终,第一种情况中勤奋的工程师会变成第二种情况中经验丰富但误解的工程师!

当你的工程师反复查 bug 或意外行为时,缺陷疲劳就会发生,他们会感到精神被掏空。过了一段时间后,重复的调查完全停止。如果很有可能只是在浪费时间,那么工程师需要有很强的自我意识和自我控制才能一遍又一遍地查这些缺陷。

现实情况是:我们大多数人没有时间调查环境缺陷,所以我们依赖这些快速的认知偏见来节省时间。这可能导致错误地总结它们是环境问题……或者错误地总结它们不是环境问题。

反质量文化如何影响 QA 工程师

反质量文化会导致 QA 工程师士气低落。他们字面上就是质量保证,如果他们周围都是缺陷并且需要规避工作,这会让工作变得非常困难,坦白地说,这是令人沮丧的。

缺陷疲劳也会影响 QA 工程师,在主要职责是查找缺陷的角色中,这是一种很危险的习惯。我将在下一节中进一步探讨这一点。

QA 工程师可能是预发布环境中最频繁的用户:这是我们运行自动化测试和执行探索性测试的地方。如果你的公司不投入时间确保 QA 能够在不断遇到环境问题的情况下履行其角色,他们可能会另谋高就。或者,在另一常见的情况下,你剩下的 QA 工程师的生产力较低,没有发挥他们的全部潜力,这确实很可惜。

更高的生产问题风险

如果你的预发布环境充满缺陷,在测试期间可能会发生以下情况。一个 QA 工程师可能会经常遇到一个小的环境缺陷。尽管这些缺陷很小,但它们确实会影响你的用户,虽然是间接的,如果这些环境缺陷的副作用影响了你的运营底线。

首先,工程师必须弄清楚这个缺陷是由于预发布环境存在问题,还是确实存在于代码中。这需要宝贵的时间。

或者,如果他们决定不调查疑似的环境问题,这可能会有后果。现实情况是:QA 并不总是正确的,这可以理解!如果一个 QA 工程师有一个截止期限,让他们感到压力,并遇到一个“可能”是环境问题的东西,他们很有可能允许更改继续前进,因为他们认为这不是一个真正的问题,或者他们已经那么疲劳,以至于没有将其注册为一个问题。 QA 工程师也不是万能的。

度量自动化测试效果的10个指标

低代码自动化测试平台的普及,测试同学代码能力的提升使得目前自动化测试已经成了测试工作中非常重要的组成部分,不管是由于 kpi 压力也好,还是因为需要消除其他方面的质疑声音也罢,我们经常需要在工作中制定一些可以度量的指标来描述某项工作或者改进的实际效果。那么有哪些指标可以去度量自动化测试的最终效果呢,这里给大家一些常见指标作为参考。

可自动化率

这个指标主要是描述所有的测试用例中有多少的用例可以被用自动化的方式进行回归,毕竟有一些用例可能还是要手动去执行的,这个值越高那么进行自动化的边际成本可能就越低。

计算公式:可自动化率 = (可以实现自动化的用例数量 / 用例总数)* 100

自动化脚本 bug 发现率

这个指标可以直观的描述自动化测试的效果,你可以通过这个指标来评估当前的投入产出比是否可以接受,另外在不同的测试环境中的效果应该是不一样的,举例来说在测试环境中我们可能主要是进行新功能的测试,那么发现的大多数问题可以都是来自手工测试,但是在 staging 环境或者说是预发布环境,我们应该主要通过自动化脚本来发现 bug,所以这个效果值应该相对高一些。

计算公式:(自动化测试发现的 bug 数 / 有效 bug 数)* 100

用例通过率

这个指标用来衡量用例的稳定性和自动化测试的实际效率,毕竟如果通过率低的话就意味着我们需要花费大量的时间去定位运行失败的原因。在多次测试中,通过率如果明显下降那么可能意味着:要么是我们的用例不稳定,不值得信赖;要么是本次的发布中包含了太多的 bug。

计算公式:(通过的用例数 / 执行的用例数)* 100

用例执行时间

天下武功,唯快不破。如果用例执行的速度太慢那么我们就没有办法在代码部署后迅速的给开发人员以反馈,浪费时间就是浪费生命。

计算公式:用例结束时间 - 用例开始时间

自动化测试用例覆盖率

耳熟能详的概念,也是很多团队都会追求的一个指标,覆盖率越高就证明测试回归的效率越高,这是一个需要长期追踪的指标,kpi 里寻常见,okr 前几度闻。

计算公式:(自动化用例数 / 用例总数)* 100

自动化用例异常率

顾名思义的指标,值得去长期关注的指标,其实就是通过率的另一种体现,失败率高可能意味着系统或产品的行为发生了更新,用例也需要进行相应的修改了。

计算公式:每次用例执行(失败用例数 / 执行的用例数)* 100

构建异常率

用例追踪 cicd 中构建质量的指标,异常率越高可能就意味着代码质量相对较差。

计算公式:(构建失败次数 / 构建总数)* 100

迭代中的自动化测试创建率

理论上说我们这个迭代开发的功能就应该在该迭代中被自动化用例所覆盖,迭代完成之后补作业的行为是不推荐的。这个指标可以告诉我们我们离该目标还有多少距离。

计算公式:(本迭代中创建的用例数 / 非本迭代中创建的用例数)* 100

自动化进度

我们的目标是将所有可以自动化的用例都进行自动化,这个指标告诉我们距离这个小目标实现有还有多少路要走。

计算公式:(当前自动化用例总数 / 可以被自动化的用例数)* 100

最恶心的测试用例--现实生活中的反模式测试行为

看到一篇吐槽测试用例的文章https://itnext.io/the-worst-test-suite-testing-anti-patterns-experienced-in-real-life-24fd13ee3ddd,觉得挺有意思的,没啥新意,不过也确实是我们会遇到的问题,或者说是我们生活的一部分。顺手翻译了一下,下面是文章内容。

我认为这里不需要介绍,我将告诉您我遇到的最糟糕的测试套件(testsuit)是什么样子,以及它是如何运作的。

我提前警告您,这篇文章会让您感到恶心,皮肤发痒,工程技能受挫。

我将介绍的反模式将以恶心程度进行排名,从 🤮 表示糟糕到 🤮🤮🤮 表示完全不可原谅。 所有的反模式都很糟糕,但其中一些我从未在其他地方见过,我认为对它们进行排名将强调它们的隐蔽性。

在阅读本文时,整个套件大约有 10 个测试文件。其中 9 个是“合理的”,第十个则是一场噩梦:它有大约 3000 行代码,总共组合了约 80 个测试用例。测试套件的约 95%都在这个文件中。

除了测试用例之外,测试使用的所有工具都散落在这个文件中。

混合测试类型

恶心程度: 🤮

该文件包含了许多不同类型的测试——从单元测试到组件测试,再到端到端测试。有些测试非常难以确定测试类型——有些单元测试通过运行系统的主要部分来测试特定的小功能,而在其他情况下,通过调用系统的内部功能序列来执行主要的端到端测试。

为什么测试被编号?

恶心程度: 🤮🤮🤮

所有的测试名称都被编号了!所有的测试都采用了 TestXX_what-the-test-checks 的形式。

这是一个重要的警示信号,当我加入这个项目时,我没有完全意识到它的重要性。大约工作了两个月后,显然这些测试之间的顺序是有问题的!这些数字是为了强制排序而存在的。这些测试是相互依赖的。

不用说,当我移动一些测试以使那个庞大的文件变得更清晰时,我是以艰难的方式学到了这一点。

如果我想添加一个测试,它必须与其他测试正确排序。这创造了一种荒谬的情况,我必须正确命名测试以便按正确的顺序运行。因此,如果我想让一个测试在 Test34_XXX 和 Test34_YYY 之间运行,我必须将我的测试命名为 Test341_ZZZ,以确保字典顺序正确 🤯

匿名测试

恶心程度: 🤮

关于测试名称,还有一件事——其中一些是匿名的——这些测试并没有说明它们实际覆盖的内容,例如:test19_requirement_59_passes 或者最受欢迎的 test87_process_works。

有些测试只有在我引入了使它们失败的更改后,我才知道它们测试的是什么,这迫使我进行调查工作以弄清楚它们在做什么。

(这不是原文,这只是我的补充:这种情况就是测试用例的名字没有任何的意义,没人知道这个用例在做什么)

断言?它们只是建议

恶心程度: 🤮🤮🤮

一些测试没有以断言结束。您当然会问一个没有断言的测试在做什么?

在这些测试中,测试的顶部有一条注释,指示“用户”去做某事。通常是像“转到日志文件并检查是否存在格式为 X - Y - Z 的日志消息”。

不用说,这并没有说明日志文件在哪里,如果有多个文件(由于日志轮换配置)该怎么办。而且,在某些情况下,这些说明已经过时,日志消息自“测试”和其说明编写以来已经发生了变化。

这些测试显然总是通过的,项目移交期间没有人告诉我这些事情,我是在添加一个功能时偶然发现有一个测试,其名称表明它测试的是我实现的过时功能的相反面。它显然通过了(因为它没有断言)。

我删除了所有这些测试,再也没有回头看过。

(这不是原文,这只是我的补充:这种情况就是只执行动作不做断言,基本上大部分同学入门的时候都会经历这个阶段。)

复杂和隐晦的输入

恶心程度: 🤮

系统的测试输入相当复杂,大多数测试都基于一个单独的输入文件。除了“刚好足够让测试通过”的输入之外,它包含的内容相当隐晦。没有人真正记得这个测试文件是如何创建的。

为了将每个测试带到相关状态,散布在 3000 行代码中,有一些实用方法来操作输入文件。它们都没有解释它们的作用,通常被称为 prepare_for_test78 之类的名称。

每当我们需要更改输入时,我们都会有点儿心痛 🥲

(这不是原文,这只是我的补充:这种情况就是准备的数据不具备可读性,没人知道这些数据是做什么的。)

拖累的共享状态

🤮 恶心程度: 🤮🤮