端到端测试

POM是一种被Selenium发扬光大的端到端测试模式.
一个使用POM的项目会在测试时为页面创建的对象, 对象被用来封装关于页面的常量和方法.
本质是在测试中运用封装和重构思想.
例如, 对象的成员可以是以页面上的元素命名的字符串, 字符串值是元素的选择器.
通过为选择器字符串命名, 而不是直接在测试中插入字符串的方式, 可以降低维护成本.
更进一步的做法是将与选择器相关的行为也封装成方法, 在测试用例里不直接访问页面, 只使用页面对象.
在实践POM时, 人们可能对POM是否应该包含断言产生分歧:
  • 包含断言显然会为POM增加过多的职责
  • 不包含断言显然会导致大量样板代码被重复编写
WebDriver协议是一个已经被标准化的W3C工作草案, 源于Selenium WebDriver框架.
它定义了一种基于HTTP的协议, 实现此协议的浏览器可以提供常见的自动化功能.
WebDriver协议在浏览器里的实现情况:
https://wpt.fyi/results/webdriver/tests?label=master&label=experimental&aligned
很有年头的浏览器自动化库, 它的优点是支持多种编程语言和市面上所有主流浏览器.
使用WebDriver协议(过去使用名为JSONWireProtocol的协议), 支持浏览器需要安装对应的驱动程序.
尽管Selenium WebDriver长久以来被用于E2E测试, 但它普遍被认为是不稳定的(flaky), 因此催生出了Puppeteer.
2018年宣布的Selenium4支持调用CDP API, 然而直到2021年9月, 才刚发布第一个RC版本.
自动化测试框架, 同时支持WebDriver协议和Chrome DevTools协议, 只支持JavaScript.
本质上是Selenium WebDriver的人性化版本, 并且支持CDP比Selenium早.
链式风格的测试框架.
正处于Alpha阶段.
基于WebDriver协议的iOS, Android, Windows应用测试框架.
该框架被普遍认为是缓慢, 脆弱, 复杂的.
Chrome DevTools Protocol是Chromium的调试协议.
它的性能比WebDriver协议快20%, 并且支持访问更低级的功能.
由Chrome开发团队支持的专用于Chromium浏览器的自动化库,
使用DevTools协议, 用于以Headless形式使用Chromium, 它只支持JavaScript.
Puppeteer会自动安装对应版本的Chromium浏览器,
这使得Puppeteer从来不会遇到因版本不匹配而导致的兼容性问题.
微软开发的可用于Firefox和Chromium浏览器的自动化库, 支持多种编程语言, 使用DevTools协议.
Playwright后于Puppeteer发布, API和Puppeteer高度相似, 相当于Puppeteer的通用版本.
该项目是为E2E测试专门创建的, 提供专门的测试函数框架 @playwright/test,
因此对E2E测试的场景的支持比Puppeteer更自然.
Playwright还对Android和Electron平台提供实验性支持.
Playwright对非Chromium系浏览器的DevTools支持是通过补丁实现的,
这也是为什么Playwright需要下载专门的(打过补丁的)浏览器二进制文件:
https://github.com/microsoft/playwright/tree/master/browser_patches
需要注意的是, 自Firefox 86开始, Firefox实现了DevTools协议的子集.
Playwright的Github star数很多, 但npm包的下载量却和Testcafe差不多, 它的测试模块下载量更低.
链式风格的E2E测试框架.
Web E2E测试领域的明星, 无论是Star数还是下载量还是都远超包括Selenium在内的所有对手.
不使用Selenium, 而是实现了自己的架构, 使用已安装的Chromium系浏览器和Firefox.
可以用来做已经部署到生产环境的网站的冒烟测试.
测试的启动速度比其他方案要慢一些, 但仍然是值得的.
由于该项目具有GUI, 无法直接在ssh里启动, 必须在宿主机上的终端里运行.
Cypress准备测试环境时依赖于:
  • cy.exec 调用本地程序, 通常用来调用JavaScript脚本.
  • cy.request 调用服务器API.
  • cy.task 调用插件命令(将准备测试环境的代码编写成task插件).
几乎所有与变量相关的操作都需要用Cypress的API来完成, 而不能用JavaScript来完成.
Cypress的测试框架固定为Mocha+Chai.
  • 不支持多标签页, 会在新标签页打开的链接很常见, 因此会经常遇到此问题.
    有两种主流的替代方案:
    1. 1.
      只检测链接的URL是否正确.
    2. 2.
      删除链接的target属性后再点击.
  • 不支持文件上传
  • 不支持iframe(尽管有办法做到这一点)
  • 不支持等待网络空闲:
    https://github.com/cypress-io/cypress/issues/1773
Cypress提供了尚处于Alpha阶段的组件测试功能.
与一般的组件测试的不同之处在于, Cypress的组件测试是在真实浏览器里运行的.
虽然Cypress官方只支持功能测试, 但Cypress已经有了一些视觉测试的方案.
https://github.com/palmerhq/cypress-image-snapshot
由于Cypress不支持等待网络空闲, 因此页面里的图片加载情况会导致差异.
https://github.com/meinaart/cypress-plugin-snapshots
由于在运行所有测试用例时会出现错误, 无法使用此插件:
  • https://github.com/meinaart/cypress-plugin-snapshots/issues/10
  • https://github.com/cypress-io/cypress/issues/3090
尽管在Cypress里可以使用POM模式, 但并不推荐这么做, 因为:
  • Cypress的链式代码本身很容易阅读.
    使用POM模式会降低可读性, POM作为中间层很大程度上是多余的.
  • Cypress可以用"自定义命令"或者将代码片段包装成函数来重用代码, 而不是创建POM.
  • Cypress鼓励用常量提取字符串, 而不是使用POM的字段.
  • POM作为对象, 很容易引入额外的状态, 这对测试不利.
Cypress的代码是自动等待的, 并且会自动处理重试和超时情况, 因此不再需要像传统E2E方案那样等待状态到位.
这同时也允许Cypress的代码维持同步风格, 避免async和await关键字使得代码更清晰.
Cypress里的一些API会自动具有断言功能, 这有助于在正确的位置抛出错误.
Cypress最明显的优势是具有一个调试GUI, 它提供以下重要功能:
  • 详细解释测试过程
  • 提供快照和时间旅行功能
  • 生成页面元素的唯一选择器
一项实验性功能, 可以录制用户操作, 生成测试脚本.
  • .get() 根据CSS选择器查找元素.
  • .contains() 根据文本查找元素.
  • .as() 为当前选择的元素创建别名.
  • .should() 断言一个元素应该是怎样的.
  • .and() should的别名, 语义上相当于连接之前的断言, 形成逻辑与.
  • .click() 点击元素
  • .dblclick() 双击元素
  • .rightclick() 右键点击元素
  • .type() 输入文本.
  • .blur() 取消元素的焦点
  • .focus() 使元素获得焦点
  • .clear() 清除input或textarea的值.
  • .check() 选中checkbox或radio.
  • .uncheck() 取消选中checkbox或radio.
  • .select() 选择select中的option.
  • .trigger() 根据事件名触发事件.
  • .invoke() 调用jQuery方法(Cypress会自动将元素包装成jQuery元素), 常用于模拟悬停(hover)事件.
    • .invoke('show') 模拟悬停
  • .its() 取得元素/对象的属性.
  • .intercept() 以编程方式spy/mock网络访问, 数据来源可以是fixtures目录下的文件.
    使用时可能要配合 .wait(), 用于等待相关的网络访问完成响应.
Cypress高度推荐使用 data-cy 作为选择器, 因为其他选择器都太脆弱.
cy.contains 根据文本查找元素, 因此它会在文本改变后测试失败.
Cypress建议在需要测试失败的情况下使用 cy.contains, 在其他场合使用 data-cy.
链式风格的E2E测试框架, 不使用WebDriver或其他测试软件, 使用系统上已安装的浏览器.
Testcafe和Cypress很相似, Testcafe实际上比Cypress更早推出.
尽管Github的Star数很多, 但npm包的下载量不及Star数更少的WebdriverIO.
非常糟糕的代码气味, 会让人怀疑开发团队的品味.
Google开发的Android UI灰盒测试框架, 被认为比Appium好得多.
要求应用是Native应用.
Apple于2015年推出的UI测试框架, 建立在XCTest之上.
要求应用是Native应用.
用于React Native应用的灰盒E2E测试框架, 被认为比Appium好.
要求使用macOS和Xcode.