Cypress 测试数据管理 #
什么是 Fixtures? #
Fixtures 是 Cypress 提供的测试数据管理机制,用于将测试数据与测试代码分离,使测试更加清晰和可维护。
text
┌─────────────────────────────────────────────────────────────┐
│ Fixtures 的优势 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 数据与代码分离 │
│ ✅ 数据可复用 │
│ ✅ 易于维护 │
│ ✅ 支持多种格式 │
│ ✅ 便于团队协作 │
│ │
└─────────────────────────────────────────────────────────────┘
Fixtures 目录结构 #
默认目录 #
text
cypress/
├── fixtures/ # 默认 fixtures 目录
│ ├── users.json # 用户数据
│ ├── products.json # 产品数据
│ ├── orders.json # 订单数据
│ └── profile.json # 配置数据
├── e2e/
└── support/
自定义目录结构 #
text
cypress/
├── fixtures/
│ ├── api/ # API 响应数据
│ │ ├── users/
│ │ │ ├── list.json
│ │ │ └── detail.json
│ │ ├── products/
│ │ │ └── list.json
│ │ └── errors/
│ │ ├── 404.json
│ │ └── 500.json
│ ├── forms/ # 表单数据
│ │ ├── login.json
│ │ └── register.json
│ └── config/ # 配置数据
│ ├── dev.json
│ └── staging.json
使用 Fixtures #
cy.fixture() #
javascript
// 加载 fixture 文件
cy.fixture('users').then((users) => {
console.log(users);
});
// 等同于
cy.fixture('users.json').then((users) => {
console.log(users);
});
在 intercept 中使用 #
javascript
// 方式一:直接使用
cy.intercept('GET', '/api/users', { fixture: 'users.json' });
// 方式二:加载后使用
cy.fixture('users.json').then((users) => {
cy.intercept('GET', '/api/users', users);
});
// 方式三:动态修改
cy.fixture('users.json').then((users) => {
users.push({ id: 3, name: 'New User' });
cy.intercept('GET', '/api/users', users);
});
在测试中使用 #
javascript
describe('用户测试', () => {
let users;
before(() => {
cy.fixture('users').then((data) => {
users = data;
});
});
it('使用 fixture 数据', () => {
cy.visit('/users');
cy.get('.user-item').should('have.length', users.length);
});
});
数据文件格式 #
JSON 格式 #
json
// cypress/fixtures/users.json
[
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"role": "admin"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane@example.com",
"role": "user"
}
]
嵌套 JSON #
json
// cypress/fixtures/api/users/detail.json
{
"user": {
"id": 1,
"profile": {
"name": "John Doe",
"avatar": "/images/avatar.jpg"
},
"settings": {
"theme": "dark",
"notifications": true
}
}
}
JavaScript 格式 #
javascript
// cypress/fixtures/users.js
module.exports = [
{
id: 1,
name: 'User ' + Date.now(),
createdAt: new Date().toISOString()
}
];
CSV 格式 #
javascript
// 加载 CSV 文件
cy.fixture('data.csv').then((csvData) => {
// 解析 CSV 数据
});
图片文件 #
javascript
// 加载图片
cy.fixture('images/logo.png', 'base64').then((logo) => {
// logo 是 base64 编码的字符串
});
动态数据生成 #
使用函数生成 #
javascript
// cypress/fixtures/generators.js
const generateUser = (overrides = {}) => {
return {
id: Math.floor(Math.random() * 1000),
name: `User ${Date.now()}`,
email: `user${Date.now()}@example.com`,
createdAt: new Date().toISOString(),
...overrides
};
};
const generateUsers = (count) => {
return Array.from({ length: count }, (_, i) => generateUser({ id: i + 1 }));
};
module.exports = {
generateUser,
generateUsers
};
使用 faker.js #
bash
npm install @faker-js/faker --save-dev
javascript
// cypress/support/data-generator.js
import { faker } from '@faker-js/faker';
export const generateUser = () => ({
id: faker.number.int({ min: 1, max: 1000 }),
name: faker.person.fullName(),
email: faker.internet.email(),
phone: faker.phone.number(),
address: {
street: faker.location.streetAddress(),
city: faker.location.city(),
country: faker.location.country()
}
});
export const generateProduct = () => ({
id: faker.number.int({ min: 1, max: 100 }),
name: faker.commerce.productName(),
price: parseFloat(faker.commerce.price()),
description: faker.commerce.productDescription()
});
动态 fixture #
javascript
// cypress/fixtures/dynamic-users.js
const generateUsers = (count) => {
return Array.from({ length: count }, (_, i) => ({
id: i + 1,
name: `User ${i + 1}`,
email: `user${i + 1}@example.com`
}));
};
module.exports = generateUsers(10);
数据复用 #
this 上下文 #
javascript
describe('用户测试', function() {
beforeEach(function() {
cy.fixture('users').as('users');
});
it('使用 this 访问 fixture', function() {
cy.log(this.users[0].name);
cy.visit('/users');
cy.get('.user-name').first().should('contain', this.users[0].name);
});
});
使用别名 #
javascript
describe('产品测试', () => {
beforeEach(() => {
cy.fixture('products').as('products');
cy.fixture('categories').as('categories');
});
it('使用别名访问数据', function() {
cy.get('@products').then((products) => {
cy.visit('/products');
cy.get('.product-item').should('have.length', products.length);
});
});
});
组合 Fixtures #
javascript
// 加载多个 fixture
beforeEach(() => {
cy.fixture('users').as('users');
cy.fixture('products').as('products');
cy.fixture('orders').as('orders');
});
// 组合使用
it('组合多个 fixture 数据', function() {
const order = {
user: this.users[0],
products: this.products.slice(0, 2),
total: this.products[0].price + this.products[1].price
};
cy.intercept('POST', '/api/orders', order);
});
数据驱动测试 #
参数化测试 #
javascript
// cypress/fixtures/test-cases.json
[
{ "input": "valid@email.com", "expected": true },
{ "input": "invalid-email", "expected": false },
{ "input": "", "expected": false },
{ "input": "user@domain", "expected": false }
]
javascript
describe('邮箱验证测试', () => {
beforeEach(() => {
cy.fixture('test-cases').as('testCases');
});
it('验证各种邮箱格式', function() {
this.testCases.forEach(({ input, expected }) => {
cy.get('#email').clear().type(input);
cy.get('.validate-button').click();
if (expected) {
cy.get('.success').should('be.visible');
} else {
cy.get('.error').should('be.visible');
}
});
});
});
使用 test.each #
javascript
describe('计算器测试', () => {
const testCases = [
{ a: 1, b: 2, expected: 3 },
{ a: 5, b: 3, expected: 8 },
{ a: -1, b: 1, expected: 0 }
];
testCases.forEach(({ a, b, expected }) => {
it(`${a} + ${b} = ${expected}`, () => {
cy.get('#a').type(a);
cy.get('#b').type(b);
cy.get('.calculate').click();
cy.get('#result').should('contain', expected);
});
});
});
环境特定数据 #
多环境配置 #
text
cypress/fixtures/
├── config/
│ ├── development.json
│ ├── staging.json
│ └── production.json
└── users.json
javascript
// cypress/support/e2e.js
before(() => {
const env = Cypress.env('environment') || 'development';
cy.fixture(`config/${env}`).as('config');
});
条件加载 #
javascript
const getFixture = (name) => {
const env = Cypress.env('environment') || 'development';
try {
return cy.fixture(`${env}/${name}`);
} catch {
return cy.fixture(name);
}
};
数据管理最佳实践 #
1. 合理组织目录结构 #
text
cypress/fixtures/
├── api/ # API 响应
│ ├── users/
│ ├── products/
│ └── orders/
├── forms/ # 表单数据
├── config/ # 配置数据
└── test-data/ # 测试用例数据
2. 使用语义化命名 #
javascript
// ✅ 好的命名
users-list.json
user-detail.json
user-create-request.json
user-create-response.json
// ❌ 不好的命名
data1.json
temp.json
test.json
3. 保持数据最小化 #
json
// ✅ 好的做法 - 只包含必要字段
{
"id": 1,
"name": "John",
"email": "john@example.com"
}
// ❌ 不好的做法 - 包含过多字段
{
"id": 1,
"name": "John",
"email": "john@example.com",
"phone": "1234567890",
"address": "...",
"preferences": "...",
"metadata": "..."
}
4. 使用模板和工厂 #
javascript
// cypress/fixtures/templates/user.json
{
"id": 1,
"name": "Template User",
"email": "template@example.com"
}
// 测试中使用
cy.fixture('templates/user').then((template) => {
const user = {
...template,
name: 'Custom Name',
email: 'custom@example.com'
};
});
完整示例 #
用户管理测试 #
javascript
// cypress/fixtures/users/list.json
[
{ "id": 1, "name": "John Doe", "email": "john@example.com", "role": "admin" },
{ "id": 2, "name": "Jane Smith", "email": "jane@example.com", "role": "user" },
{ "id": 3, "name": "Bob Wilson", "email": "bob@example.com", "role": "user" }
]
// cypress/fixtures/users/detail.json
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"role": "admin",
"profile": {
"avatar": "/avatars/john.jpg",
"bio": "Software Developer"
}
}
// cypress/fixtures/users/create-request.json
{
"name": "New User",
"email": "newuser@example.com",
"role": "user"
}
// cypress/fixtures/users/create-response.json
{
"id": 4,
"name": "New User",
"email": "newuser@example.com",
"role": "user",
"createdAt": "2024-01-01T00:00:00Z"
}
javascript
// cypress/e2e/users.cy.js
describe('用户管理', () => {
beforeEach(() => {
cy.fixture('users/list').as('usersList');
cy.fixture('users/detail').as('userDetail');
cy.fixture('users/create-request').as('createRequest');
cy.fixture('users/create-response').as('createResponse');
});
context('用户列表', () => {
beforeEach(function() {
cy.intercept('GET', '/api/users', this.usersList).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
});
it('显示用户列表', function() {
cy.get('.user-item').should('have.length', this.usersList.length);
});
it('显示用户详情', function() {
cy.intercept('GET', '/api/users/1', this.userDetail).as('getUserDetail');
cy.get('.user-item').first().click();
cy.wait('@getUserDetail');
cy.get('.user-detail').within(() => {
cy.get('.name').should('contain', this.userDetail.name);
cy.get('.email').should('contain', this.userDetail.email);
});
});
});
context('创建用户', () => {
it('创建新用户', function() {
cy.intercept('POST', '/api/users', this.createResponse).as('createUser');
cy.visit('/users/new');
cy.get('#name').type(this.createRequest.name);
cy.get('#email').type(this.createRequest.email);
cy.get('#role').select(this.createRequest.role);
cy.get('.submit').click();
cy.wait('@createUser').its('request.body').should('deep.equal', this.createRequest);
cy.get('.success-message').should('be.visible');
});
});
context('数据驱动测试', () => {
const roles = ['admin', 'user', 'guest'];
roles.forEach((role) => {
it(`创建 ${role} 角色用户`, function() {
const userData = {
...this.createRequest,
role: role
};
cy.intercept('POST', '/api/users', {
...this.createResponse,
role: role
}).as('createUser');
cy.visit('/users/new');
cy.get('#name').type(userData.name);
cy.get('#email').type(userData.email);
cy.get('#role').select(userData.role);
cy.get('.submit').click();
cy.wait('@createUser');
});
});
});
});
使用 Faker 生成数据 #
javascript
// cypress/support/data-generator.js
import { faker } from '@faker-js/faker';
export const createUser = (overrides = {}) => ({
name: faker.person.fullName(),
email: faker.internet.email(),
phone: faker.phone.number(),
...overrides
});
export const createProduct = (overrides = {}) => ({
name: faker.commerce.productName(),
price: parseFloat(faker.commerce.price({ min: 10, max: 1000 })),
description: faker.commerce.productDescription(),
...overrides
});
export const createOrder = (overrides = {}) => ({
id: faker.number.int({ min: 1000, max: 9999 }),
items: Array.from({ length: 3 }, () => createProduct()),
total: parseFloat(faker.commerce.price({ min: 100, max: 500 })),
...overrides
});
javascript
// cypress/e2e/orders.cy.js
import { createUser, createProduct, createOrder } from '../support/data-generator';
describe('订单测试', () => {
it('创建订单', () => {
const user = createUser();
const order = createOrder({ user });
cy.intercept('POST', '/api/orders', order).as('createOrder');
cy.visit('/orders/new');
cy.get('#customer-name').type(user.name);
cy.get('#customer-email').type(user.email);
cy.get('.submit').click();
cy.wait('@createOrder');
});
});
下一步 #
现在你已经掌握了 Cypress 测试数据管理的方法,接下来学习 自定义命令 了解如何创建可复用的测试命令!
最后更新:2026-03-28