Cypress最佳实践------写出高效又好维护的测试
用Cypress写测试不难,但写出稳定、简洁、易维护的测试却需要技巧。这一章咱们聊聊实战中的最佳实践,从项目结构到代码细节,帮你避开"写时一时爽,维护火葬场"的坑。
一、基础配置:让测试跑起来更顺畅
1. 配置baseUrl
减少重复代码
在cypress.json
里设置baseUrl
,测试中访问页面时就不用写完整URL了,既简洁又方便切换环境:
json
// cypress.json
{
"baseUrl": "http://localhost:7077"
}
javascript
// 直接写相对路径,自动拼接baseUrl
cy.visit('/login') // 等同于访问http://localhost:7077/login
2. 禁用不必要的等待,依赖自动重试
传统测试工具里,我们习惯用sleep(1000)
等待页面加载,但Cypress的命令会自动等待元素可操作(默认等4秒),完全不用手动加等待。
javascript
// 错误示例:多余的等待
cy.visit('/dashboard')
cy.wait(2000) // 没必要!cy.get会自动等待
cy.get('[data-cy=stats]').should('contain', '销售额')
// 正确做法:依赖Cypress的自动重试
cy.visit('/dashboard')
cy.get('[data-cy=stats]').should('contain', '销售额') // 会自动等元素加载
二、测试用例设计:聚焦核心场景
1. 避免"大而全"的用例,拆分独立场景
一个用例只测一个功能点,比如"登录成功""登录失败(密码错误)""登录失败(账号为空)"应该拆成3个用例,而不是写在一个it
里。
好处:失败时能精准定位问题,且可以单独重跑某个场景。
2. 动态生成用例,应对多组数据
如果多个场景的步骤相同,只是输入/输出不同(比如测试登录时的各种错误提示),用数据驱动动态生成用例,不用复制粘贴代码:
javascript
// 测试数据:不同输入对应的预期结果
const testData = [
{ username: '', password: '', expectError: '请输入账号' },
{ username: 'jane', password: 'wrong', expectError: '密码错误' },
{ username: 'invalid', password: '123', expectError: '账号不存在' }
]
describe('登录错误场景', () => {
// 循环数据生成用例
testData.forEach((data) => {
it(`输入${data.username}/${data.password}时,提示${data.expectError}`, () => {
cy.visit('/login')
cy.get('input[name=username]').type(data.username)
cy.get('input[name=password]').type(data.password)
cy.get('[data-cy=login-btn]').click()
cy.get('[data-cy=error-msg]').should('contain', data.expectError)
})
})
})
三、代码复用:减少重复劳动
1. 用Custom Commands
封装重复操作
把常用步骤(比如登录、添加商品到购物车)封装成自定义命令,在cypress/support/commands.js
里定义:
javascript
// 定义登录命令
Cypress.Commands.add('login', (username, password) => {
cy.visit('/login')
cy.get('input[name=username]').type(username)
cy.get('input[name=password]').type(password)
cy.get('[data-cy=login-btn]').click()
})
之后在所有测试用例里直接调用:
javascript
// 测试中直接用cy.login()
it('登录后访问个人中心', () => {
cy.login('jane.lane', 'password123') // 复用登录逻辑
cy.visit('/profile')
cy.get('[data-cy=username]').should('contain', 'jane.lane')
})
2. 用fixture
管理测试数据
测试中用到的静态数据(比如用户信息、接口模拟数据)别硬编码在代码里,放在cypress/fixtures
文件夹下,用cy.fixture()
读取:
json
// cypress/fixtures/user.json
{
"username": "jane.lane",
"password": "password123",
"nickname": "简"
}
javascript
// 测试中读取fixture数据
it('使用fixture数据登录', () => {
cy.fixture('user.json').then((user) => {
cy.login(user.username, user.password) // 用fixture里的数据
})
})
四、断言与调试:让失败原因一目了然
1. 用清晰的断言描述预期结果
断言不仅要判断"对不对",还要说明"预期是什么",方便其他人看懂测试意图:
javascript
// 不好的断言:只知道错了,不知道预期是什么
cy.get('[data-cy=user-count]').should('eq', 5)
// 好的断言:清晰说明预期
cy.get('[data-cy=user-count]')
.should('contain', '5')
.and('be.visible') // 同时验证可见性
2. 测试失败时自动截图/录屏
Cypress默认会在测试失败时自动截图,无头模式(cypress run
)下还会录屏,这些文件保存在cypress/screenshots
和cypress/videos
里,配合日志能快速定位问题。
如果想手动截图,用cy.screenshot()
:
javascript
// 在关键步骤手动截图
cy.get('[data-cy=order-summary]').screenshot('订单摘要')
五、避坑指南:这些做法要不得
- 别测UI样式细节:比如颜色、字体大小(容易随设计变更,增加维护成本),专注测功能逻辑。
- 别依赖第三方服务 :测试中用到的接口尽量用
cy.intercept()
mock掉,避免因第三方服务不稳定导致测试失败。 - 别在测试中操作数据库:直接改数据库会污染测试环境,应该通过接口或UI操作准备数据。