端到端(End-to-End,简称E2E)测试是一种软件测试方法,主要关注系统或应用程序从用户界面到后端服务器的所有组件和功能的正确性。端到端测试的目标是确保整个系统在各种场景下都能正常工作,以满足用户需求和预期。

需要进行端到端测试的原因如下:

  1. 确保系统完整性:端到端测试可以确保整个系统的功能和性能都符合预期,从而避免出现由于某个组件的故障而导致整个系统崩溃的情况。
  2. 提高测试覆盖率:通过端到端测试,可以覆盖整个系统的所有可能的使用场景,从而提高测试的覆盖率,减少遗漏测试的情况。
  3. 降低风险:通过端到端测试,可以及时发现系统中存在的问题和缺陷,并及时修复,从而降低项目的风险。
  4. 提高用户体验:通过端到端测试,可以确保系统在各种场景下都能正常工作,从而提高用户的体验和满意度。

总之,端到端测试是一种非常重要的软件测试方法,它可以帮助开发人员和测试人员全面地评估系统的性能和功能,从而保证软件的质量和稳定性。

常见的端到端测试工具有老牌的cypress和新生代playwright

cypress

安装启动

使用命令安装

$ pnpm install cypress -D

安装完成之后使用命令来启动(如果是typescript项目记得在ts配置中添加类型:types: [“cypress”])

$ npx cypress open

之后会启动一个窗口

image-20230517221443492

选择端到端测试,如果是第一次运行会提示生成一些文件,包括cypress.config.js等。

然后会进入选择Chrome或者Electron(浏览器cypress只支持chrome)。

image-20230517221722488

进入Chrome之后的界面如下

image-20230517221836936

我们可以在这创建测试用例,运行测试用例等

编写测试用例

cypress的API风格有点像JQuery,一系列的链式调用,如下

describe('E2E test demo', () => {
  beforeEach(() => {
    cy.visit('http://localhost:5500/src/e2e')
  })

  it('loaded', () => {
    cy.get('#ipt').should('have.value', 'hello0')
    cy.get('button').should('have.text', 'change')
  })
  
  it('click', () => {
    cy.get('#ipt').should('have.value', 'hello0')
    cy.get('button').click()
    cy.get('#ipt').should('have.value', 'hello1')
    cy.get('button').click()
    cy.get('#ipt').should('have.value', 'hello2')
  })
})

和Jest的风格也比较接近,对于新手来说比较好入门,测试用例语义化很好,非常便于理解。

钩子

Cypress采用了Mocha的bdd语法,所以如果之前写过Jest,会非常相似。

Cypress中常用的一些钩子如下:

  • describe():声明一个测试用例组
  • context():describe的别名
  • it():声明一个测试用例
  • before():在当前组开始执行用例前执行一次
  • beforeEach():在每个测试用例执行前执行一次
  • afterEach():在每个测试用例执行后执行一次
  • after():在当前组所有用例执行完之后执行一次
  • .only():只运行当前用例
  • .skip():跳过当前用例
断言

Cypress的断言继承了Chai,这使得我们非常容易编写测试用例,有两种形式可以编写测试用例

selector.should('not.equal', 'Jane')
expect(name).to.not.equal('Jane')

这两种形式是一个意思

选择器
命令 用法
.as() 分配别名以供以后使用。稍后在cy.get()查询或cy.wait()命令中引用别名。
.children() 获取一组DOM元素中每个元素的子元素。
.closest() 获取与选择器匹配的第一个祖先元素。
.contains() 按文本内容选择DOM元素。
.document() 获取活动页面的window.document
.eq() 从集合中按索引选择DOM元素。
.filter() 使用选择器过滤元素。
.find() 使用选择器查找后代元素。
.first() 选择集合中的第一项。
.focused() 获取当前聚焦的DOM元素。
.get() 通过选择器查找DOM元素,或读取之前使用.as()命令创建的别名。
.hash() 获取活动页面的URL哈希值。
.invoke() 在先前产生的主题上调用函数。
.its() 获取先前产生的主题的属性值。
.last() 选择集合中的最后一项。
.location() 获取活动页面的window.location对象。
.next() 获取下一个兄弟元素。
.nextAll() 获取所有后续兄弟元素。
.nextUntil() 获取所有后续兄弟元素
.not() 使用选择器过滤选定的元素。
.parent() 获取DOM元素的父元素。
.parents() 获取DOM元素的所有父元素。
.parentsUntil() 将所有父元素获取到选择器。
.prev() 获取前一个兄弟元素。
.prevAll() 获取所有以前的兄弟元素。
.prevUntil() 获取所有之前的兄弟元素,直到到达选择器。
.root() 获取根DOM元素。
.shadow() 遍历到元素的影子DOM。
.siblings() 获取所有兄弟元素。
.title() 获取document.title文档. title属性。
.url() 获取活动页面的URL。
.window() 获取window对象的活动页面。
事件
命令 用法
.check() 检查复选框或单选元素。
.clear() 清除输入或文本区域的值。
.click() 单击DOM元素。
.dblclick() 双击DOM元素。
.rightclick() 右键单击DOM元素。
.scrollIntoView() 将元素滚动到视图中。
.scrollTo() 滚动到特定位置。
.select() <select>中选择一个<option>.
.selectFile() 选择HTML5输入元素中的文件,或模拟将文件拖动到浏览器中。
.trigger() 触发DOM元素上的事件。
.type() 键入DOM元素。
.uncheck() 取消选中复选框。

详细API可见官网文档

playwright

安装

在开始使用playwright之前先来安装必要的依赖

$ pnpm install playwright @playwright/test -D

playwright 负责提供相关的命令行工具,@playwright/test负责提供测试相关的API。

配置文件

为了更好的提供类型支持,可以使用defineConfig方法来定义配置文件,一个配置文件的大概结构如下

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // 测试文件的目录,相对于配置文件
  testDir: 'tests',
  // 并行运行所有测试
  fullyParallel: true,
  // 测试报告的形式
  reporter: 'html',
  use: {
    // baseURL page.goto('/') 相对路径
    baseURL: 'http://127.0.0.1:5500',
    // 主题.
    colorScheme: 'dark',
    // 位置信息.
    geolocation: { longitude: 12.492507, latitude: 41.889938 },
    // 语言.
    locale: 'zh-CN',
    // 需要的权限.
    permissions: ['geolocation'],
    // 时区.
    timezoneId: 'Asia/Shanghai',
    // 窗口大小.
    viewport: { width: 1280, height: 720 },
  },
  // 浏览器配置
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
  // 在开始测试执勤啊启动开发服务器.
  webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3000',
  },
});

更多配置文件内容可见官网文档configurationuse options

命令行工具

常用的命令行工具如下

$ npx playwright install
// 确保安装了此版本Playwright所需的浏览器
$ npx playwright test
// 运行测试用例
$ npx playwright codegen
// 生成测试用例

其中 test 不加参数时会执行全部的测试用例,或者可以添加如下参数:

  • npx playwright test tests/example.spec.ts:执行指定的单个测试文件

  • npx playwright test tests/example/:执行指定目录下的测试用例

  • npx playwright test example:执行所有文件名中包含指定字符串的测试用例

  • npx playwright test tests/example.spec.ts:21:执行指定文件的指定行

  • npx playwright test -g "test example":执行所有指定标题的测试用例

  • npx playwright test --headed:在浏览器中执行测试,默认是在终端中进行测试

  • npx playwright test --worker=1:控制测试用例并行的最大限制

  • npx playwright test --reporter=line:指定测试报告的形式,可选值有list、line、dot、html、json、junit、github,如果固定使用某种报告形式可以写在配置文件中

  • npx playwright test --ui:使用UI的方式来进行测试,UI界面如下

    image-20230517203451292

更多命令行说明可见官网文档 command line或者运行命令npx playwright --help

生成代码

Playwright 比较简便的一点是可以生成代码,根据我们在页面上的操作进行录制,转为测试用例代码,我们在这个基础上进行用例的完善就可以快速地编写测试用例。

可以使用命令行工具来进行录制

$ npx playwright codegen

然后会打开一个chromium实例和一个脚本录制窗口,我们在这个chromium中操作就会被记录为测试用例的步骤。

image-20230516205825524

然后将生成的代码复制到文件中完善一下即可。

或者也可以使用VSCode插件来进行脚本录制,插件商店安装Playwright Test for VSCode,然后找到插件即可进行录制,使用VSCode录制的用例会自动保存到项目跟目录。

image-20230516210133157

测试用例常用API

钩子

playwright的常用钩子和Cypress基本类似,区别在于,playwright的所有钩子都是在test对象下的,比如describe在playwright中需要表示为test.describe,test需要从@playwright/test中引入。

小区别:Cypress中的before和after在playwright中对应的钩子是beforeAll和afterAll

断言

playwright最常用的断言形式是选择器断言,比较多就不一一解释了。

选择器

常用的选择器是page.locator和page.getByRole。locator的参数就是DOM选择器;getByRole的第一个参数时role,第二个参数是一个配置,用于过滤role。

对于下面这个html元素

<button id="btn">
  change
</button>

下面两种选择方式是一样的

page.locator('#btn')
page.getByRole('button', { name: 'change' })

更多role类型可以看一下w3c的文档

当然不止有这两个,playwright的选择器是非常丰富的,如果没有特殊需求,这两个选择器一般可以满足大部分场景。

事件

playwright的事件需要通过选择其获取Locator实例之后在实例上触发。

更多测试相关的API就不列举了,太多了,转战官网文档啃吧

对比

对比项目 Cypress Playwright
功能和用途 前端端到端测试 跨浏览器自动化测试
架构和执行方式 单线程模型 客户端-服务器架构
支持的浏览器 仅支持Chrome 支持Chrome、Firefox、WebKit(Safari的引擎)
语言支持 JavaScript、TypeScript JavaScript、TypeScript、Python、.NET
社区支持和生态系统 庞大的社区支持和活跃的开发者社区 社区支持度较高,但相对较新

此外两个框架在API风格上有着较大的差异:

  • Cypress提供了一套简洁、直观的链式调用API。这种风格使得编写测试用例变得非常清晰和易于理解;
  • Playwright的API风格更加面向对象和模块化。它将不同的功能和操作封装在各种类和方法中。

总体而言,Cypress的API更加简洁、直观,而Playwright的API更加面向对象和模块化。选择哪种API风格取决于个人偏好和项目需求。


前端小白