前端自动化测试 - 入门篇

·  阅读 1072

前端自动化测试

在平时的开发中,测试肯定与我们息息相关,但是可能大多数时候所说的测试是由我们专门的测试人员去测,或者开发人员进行自测,以上所说我们都可以把它称作手动测试,那与之对应的就是自动化测试,那什么是自动化测试呢?简单来说就是我们事先写好一些测试脚本,然后通过运行这些测试脚本,就可以判断我们的代码是否正常。

因此,我们把平时项目开发中的测试主要分为两种:

  • 手动测试
  • 自动化测试

而自动化测试,根据测试的对象,范围,场景等不同,主要分为以下几种:

  • 单元测试:验证独立的单元模块是否正常工作
  • 集成测试:验证多个单元模块间的协同工作
  • 端到端测试:从用户的角度,通过机器来模仿用户在真实浏览器中验证应用交互
  • 快照测试:验证程序的UI变化

分类

单元测试

单元测试是对应用程序最小的部分(单元)运行测试的过程。通常,测试的单元是函数,但在前端应用中,组件也是被测单元。

单元测试应该避免依赖性问题,比如不存取数据库、不访问网络等等,而是使用工具虚拟出运行环境。这种虚拟使得测试成本最小化,不用花大力气搭建各种测试环境。

单元测试的优点:

  • 提升代码质量,减少 Bug
  • 快速反馈,减少调试时间
  • 让代码维护更容易
  • 有助于代码的模块化设计
  • 代码覆盖率高

单元测试的缺点:

  • 由于单元测试是独立的,所以无法保证多个单元运行到一起是否正确

常见的 JavaScript 单元测试框架:

  • Jest
  • Mocha
  • Jasmine
  • Karma
  • ava
  • Tape
  • ...

Mocha 跟 Jest 是目前最火的两个单元测试框架,基本上目前前端单元测试就在这两个库之间选了。总的来说就是 Jest 功能齐全,配置方便,Mocha 灵活自由,自由配置。 两者功能覆盖范围粗略可以表示为:

Jest === Mocha + Chai + Sinon + mockserver + istanbul
复制代码

集成测试

人们定义集成测试的方式并不相同,尤其是对于前端。有些人认为在浏览器环境上运行的测试是集成测试;有些人认为对具有模块依赖性的单元进行的任何测试都是集成测试;也有些人认为任何完全渲染的组件测试都是集成测试。

简单来说:前端页面就是由一系列的组件组合在一起的,所以所谓的集成测试,其实就是测试这个组件放在一起,是否能够正常工作。

优点:

  • 由于是从用户使用角度出发,更容易获得软件使用过程中的正确性
  • 集成测试相对于写了软件的说明文档
  • 由于不关注底层代码实现细节,所以更有利于快速重构
  • 相比单元测试,集成测试的开发速度要更快一些

缺点:

  • 测试失败的时候无法快速定位问题
  • 代码覆盖率较低
  • 速度比单元测试要慢

端到端测试

E2E(end to end)端到端测试是最直观可以理解的测试类型。在前端应用程序中,端到端测试可以从用户的视角通过浏览器自动检查应用程序是否正常工作。

想象一下,你正在编写一个计算器应用程序,并且你想测试两个数求和的运算方法是否正确。你可以编写一个端到端测试,打开浏览器,加载计算器应用程序,单击“1”按钮,单击加号“+”按钮,再次单击“1”按钮,单击等号“=”,最后检查屏幕是否显示正确结果“2”。

image.png

编写完一个端到端测试后,可以根据自己的需求随时运行它。想象一下,相比执行数百次同样的手动测试,这样一套测试代码可以节省多少时间!

优点:

  • 真实的测试环境,更容易获得程序的信心

缺点:

  • 首先,端到端测试运行不够快。启动浏览器需要占用几秒钟,网站响应速度又慢。通常一套端到端测试需要 30 分钟的运行时间。如果应用程序完全依赖于端到端测试,那么测试套件将需要数小时的运行时间。
  • 端到端测试的另一个问题是调试起来比较困难。要调试端到端测试,需要打开浏览器并逐步完成用户操作以重现 bug。本地运行这个调试过程就已经够糟糕了,如果测试是在持续集成服务器上失败而不是本地计算机上失败,那么整个调试过程会变得更加糟糕。

一些流行的端到端测试框架:

  • Cypress(推荐)
  • Nightwatch
  • WebdriverIO
  • playwright

快照测试

快照测试类似于“找不同”游戏。快照测试会给运行中的应用程序拍一张图片,并将其与以前保存的图片进行比较。如果图像不同,则测试失败。这种测试方法对确保应用程序代码变更后是否仍然可以正确渲染很有帮助。

当然,在前端中,其实并不是比较图片,而是比较前后生成的html结构,本质上是一个字符串的比较。

哪些场景会用到快照测试呢?典型的就是组件库中,例如:ant design,vant等其实每个组件都会有对应的快照测试。

测试金字塔

首先,简单对以上集中测试方法简单总结一下:

  • 单元测试:从程序角度出发,对应用程序最小的部分(函数、组件)运行测试的过程,它是从程序员的角度编写的,保证一些方法执行特定的任务,给出特定输入,得到预期的结果。
  • 集成测试:从用户角度出发,对应用中多个模块组织到一起的正确性进行测试。
  • 快照测试:快照测试类似于“找不同”游戏,主要用于 UI 测试。
  • 端到端测试:端到端测试是从用户的角度编写的,基于真实浏览器环境测试用户执行它所期望的工作。

那到底该写哪种测试?都写,根据情况灵活分配。比较典型的就是:

  • 金字塔模式
  • 奖杯模式

image.png

image.png

奖杯模型中自下而上分为静态测试、单元测试、集成测试、e2e 测试, 它们的职责大致如下:

  • 静态测试:在编写代码逻辑阶段时进行报错提示。(代表库: ESLint、Flow、TypeScript)
  • 单元测试:在奖杯模型中, 单元测试的职责是对一些边界情况或者特定的算法进行测试。(代表库: Jest、Mocha)
  • 集成测试:模拟用户的行为进行测试,对网络请求、获取数据库的数据等依赖第三方环境的行为进行 Mock。(代表库: Jest、react-testing-library、Vue Testing Library 等)
  • e2e 测试:模拟用户在真实环境上操作行为(包括网络请求、获取数据库数据等)的测试。(代表库: Cypress)

通过前面的介绍,相信大家对自动化测试有了一个初步的了解,那实际开发中怎么用呢?


下面是针对不同的应用场景为了一些个人建议:【重点结论】

  • 如果你是开发纯函数库,建议写更多的单元测试 + 少量的集成测试
  • 如果你是开发组件库,建议写更多的单元测试、为每个组件编写快照测试、写少量的集成测试 + 端到端测试
  • 如果你是开发业务系统,建议写更多的集成测试、为工具类库、算法写单元测试、写少量的端到端测试

测试覆盖率

测试覆盖率(test coverage)是衡量软件测试完整性的一个重要指标。掌握测试覆盖率数据,有利于客观认识软件质量,正确了解测试状态,有效改进测试工作。

如何度量测试覆盖率呢?

  • 代码覆盖率
  • 需求覆盖率
  • ...

代码覆盖率

最著名的测试覆盖率就是代码覆盖率。这是一种面向软件开发和实现的定义。它关注的是在执行测试用例时,有哪些软件代码被执行到了,有哪些软件代码没有被执行到。被执行的代码数量与代码总数量之间的比值,就是代码覆盖率。

这里,根据代码粒度的不同,代码覆盖率可以进一步分为四个测量维度。它们形式各异,但本质是相同的。

● 行覆盖率(line coverage):是否每一行都执行了?

● 函数覆盖率(function coverage):是否每个函数都调用了?

● 分支覆盖率(branch coverage):是否每个if代码块都执行了?

● 语句覆盖率(statement coverage):是否每个语句都执行了?

如何度量代码覆盖率呢?一般可以通过第三方工具完成,比如 Jest 自带了测试覆盖率统计。

这些度量工具有个特点,那就是它们一般只适用于白盒测试,尤其是单元测试。对于黑盒测试(例如功能测试/系统测试)来说,度量它们的代码覆盖率则相对困难多了。

尤其是我们项目中的功能点,需求点,其实本质上就是黑盒测试,我们可以使用集成测试等不需要去关注代码具体细节,只关注需求点的输入输出是否正确等,此时用需求覆盖率去评估相对较好。

需求覆盖率

对于黑盒测试,例如功能测试/集成测试/系统测试等来说,测试用例通常是基于软件需求而不是软件实现所设计的。因此,度量这类测试完整性的手段一般是需求覆盖率,即测试所覆盖的需求数量与总需求数量的比值。

视需求粒度的不同,需求覆盖率的具体表现也有不同。例如,系统测试针对的是比较粗的需求,而功能测试针对的是比较细的需求。当然,它们的本质是一致的。

如何度量需求覆盖率呢?通常没有现成的工具可以使用,而需要依赖人工计算,尤其是需要依赖人工去标记每个测试用例和需求之间的映射关系。

对于代码覆盖率来说,广为诟病的一点就是 100% 的代码覆盖率并不能说明代码就被完全覆盖没有遗漏了。因为代码的执行顺序和函数的参数值,都可能是千变万化的。一种情况被覆盖到,不代表所有情况被覆盖到。

对于需求覆盖率来说,100% 的覆盖率也不能说“万事大吉”。因为需求可能有遗漏或存在缺陷,测试用例与需求之间的映射关系,尤其是用例是否真正能够覆盖对应的测试需求,也可能是存在疑问的。

总结

它们适用于不同的场景,有各自的优势与不足。需要注意的是,它们不是互相排斥,而是相互补充的。

关于测试覆盖率,最重要的一点应该是迈出第一步,即有意识地去收集这种数据。没有覆盖率数据,测试工作会有点像在“黑灯瞎火”中走路。有了覆盖率数据,并持续监测,利用和改进这个数据,才是一条让测试工作越来越好的光明大道。

既然测试这么好,那是不是所有代码都要有测试用例支持呢?

我认为测试覆盖率还是要和测试成本结合起来,比如一个不会经常变的公共方法就尽可能的将测试覆盖率做到趋于 100%。而对于一个完整项目,我建议前期先做最短的时间覆盖 80% 的测试用例,后期再慢慢完善。

经常做更改的活动页面我认为没必要必须趋近 100%,因为要不断的更改测试永用例,维护成本太高。

大多数情况下,将 100% 代码覆盖率作为目标并没有意义。当然,如果你在开发一个极其重要的支付应用,存在的 Bug 可能会导致数百万美元的损失,那么 100% 代码覆盖率对你是有用的。

实现传说中的 100% 代码覆盖率不仅耗时,而且即使代码覆盖率达到 100%,测试也并非总能发现 bug。有时你可能还会做出错误的假设,当你调用一个 API 代码时,假定的是该 API 永远不会返回错误,然而当 API确实在生产环境中返回错误时,你的应用就崩溃了。

测试开发方式

测试开发有两个流派:

  • TDD:测试驱动开发,先写测试后实现功能
  • BDD:行为驱动开发,先实现功能后写测试

image.png

个人推荐:

  • 建议开发功能函数库使用 TDD 方案;
  • 建议开发业务系统使用 BDD 方案;

而适合引入测试场景大概有这么几个:

  • 需要长期维护的项目。它们需要测试来保障代码可维护性、功能的稳定性
  • 较为稳定的项目、或项目中较为稳定的部分。给它们写测试用例,维护成本低
  • 被多次复用的部分,比如一些通用组件和库函数。因为多处复用,更要保障质量

总结

相信通过这节的介绍,大家对自动化测试有了一个初步的认识和了解,对其中涉及到的一些专门名词有了一个了解,但是这还远远不够,以上只是一些纯理论的介绍,接下来,还需要大家去在实际项目中去真正的使用自动化测试,才会有一个更清晰的认识。

这里再次强调一下常见这几种测试的应用场景:

  • 如果你是开发纯函数库,建议写更多的单元测试 + 少量的集成测试
  • 如果你是开发组件库,建议写更多的单元测试、为每个组件编写快照测试、写少量的集成测试 + 端到端测试
  • 如果你是开发业务系统,建议写更多的集成测试、为工具类库、算法写单元测试、写少量的端到端测试

写作不易,如果觉得对您有所帮助,欢迎大家点赞和关注哦~😊😊😊

分类:
前端
分类:
前端
收藏成功!
已添加到「」, 点击更改