Skip to content

Cypress - 数据驱动测试

Cypress - 使用 Fixtures 进行数据驱动测试

Section titled “Cypress - 使用 Fixtures 进行数据驱动测试”

数据驱动测试(Data-driven testing)是一种将测试数据与测试脚本分开存储的技术。这让你能够使用多个数据集运行相同的测试逻辑,从而提高测试覆盖率和可维护性。Cypress 主要通过其 fixtures 功能实现数据驱动测试。

Fixtures 是用于存储静态测试数据的文件。默认情况下,Cypress 会在 cypress/fixtures 文件夹中查找 fixture 文件。这些文件可以是各种格式,其中 JSON (.json) 是最常见的格式。

一个典型的 cypress/fixtures 文件夹结构可能如下所示:

cypress/
fixtures/
example.json
userCredentials.json
productData.json
integration/ (or e2e/ for Cypress 10+)
login_spec.js
// other test files

Fixture 数据通常以键值对(key-value pairs)的形式组织,尤其是在使用 JSON 时。

cy.fixture() 命令用于从 fixture 文件加载数据。然后可以在你的测试中使用这些数据。

cy.fixture(filePath)
cy.fixture(filePath, encoding)
cy.fixture(filePath, options)
cy.fixture(filePath, encoding, options)

其中:

  • filePath: fixture 文件的路径(相对于 cypress/fixtures 文件夹)。如果是 .json 文件,可以省略文件扩展名。
  • encoding: 用于读取文件的编码类型(例如,‘utf8’, ‘ascii’)。默认为 ‘utf8’。
  • options: 一个用于修改默认行为的对象。例如,timeout 可以更改等待 fixture 加载的默认等待时间。

让我们创建一个场景,使用 fixture 文件中的数据来测试登录表单。

创建一个名为 cypress/fixtures/userLogin.json 的文件,内容如下:

{
"username": "standardUser",
"password": "secret_sauce",
"invalidUsername": "lockedOutUser",
"invalidPassword": "wrong_password"
}

在你的测试文件中(例如,cypress/integration/login_ddt_spec.js 或 cypress/e2e/login_ddt_spec.cy.js):

describe('Login Functionality - Data-Driven', () => {
// Load fixture data before tests run
before(function () {
cy.fixture('userLogin').then(function (data) {
// 'this.data' now holds the content of userLogin.json
// Using standard 'function' allows 'this' to refer to the Mocha context
this.loginData = data;
});
});
it('Should login successfully with valid credentials from fixture', function () {
cy.visit('https://www.saucedemo.com/'); // Example login page
cy.get('[data-test="username"]').type(this.loginData.username);
cy.get('[data-test="password"]').type(this.loginData.password);
cy.get('[data-test="login-button"]').click();
cy.url().should('include', '/inventory.html');
});
it('Should display an error with invalid credentials from fixture', function () {
cy.visit('https://www.saucedemo.com/');
cy.get('[data-test="username"]').type(this.loginData.invalidUsername);
cy.get('[data-test="password"]').type(this.loginData.invalidPassword);
cy.get('[data-test="login-button"]').click();
cy.get('[data-test="error"]').should('be.visible')
.and('contain.text', 'Username and password do not match'); // Adjust error message as per actual application
});
});

在此示例中:

  • before 钩子在 describe 块中的任何测试运行之前,加载 userLogin.json fixture 一次。
  • cy.fixture('userLogin').then(function (data) { ... }) 使 fixture 数据在测试用例(it 块)中通过 this.loginData 可用。这里使用标准的 function() 作为回调函数很重要,这样 this 才能指向 Mocha 的测试上下文(test context)。
  • 然后,测试使用 this.loginData.username、this.loginData.password 等来填充表单字段。

如果你的 fixture 包含一个测试数据集的数组,你可以遍历它们:

Fixture 文件 cypress/fixtures/multipleUsers.json:

[
{ "username": "user1", "password": "pass1" },
{ "username": "user2", "password": "pass2" }
]

测试脚本:

describe('Multiple User Login', () => {
before(() => {
cy.fixture('multipleUsers').as('users'); // 为 fixture 数据设置别名
});
it('should attempt login for each user', function() {
// 由于在 before 钩子中设置了别名,现在可以通过 'this.users' 访问数据
this.users.forEach((userData) => {
cy.log(`Attempting login for ${userData.username}`); // 尝试登录用户 ${userData.username}
cy.visit('https://www.saucedemo.com/');
cy.get('[data-test="username"]').type(userData.username);
cy.get('[data-test="password"]').type(userData.password);
cy.get('[data-test="login-button"]').click();
// 根据每个用户的预期结果添加相应的断言
// Add appropriate assertions based on expected outcome for each user
// 为简单起见,此示例仅记录日志并尝试登录。
// For simplicity, this example only logs and attempts login.
});
});
});

在 before 或 beforeEach 钩子中使用 cy.fixture(...).as('aliasName'),可以在同一作用域的后续钩子和测试中通过 this.aliasName 访问数据。

  • 关注点分离(Separation of Concerns): 将测试数据与测试逻辑分开。
  • 可重用性(Reusability): 相同的 fixture 数据可以在多个测试中使用。
  • 可读性(Readability): 使测试更清晰、更易于理解。
  • 可维护性(Maintainability): 在不修改测试脚本的情况下更容易更新测试数据。

虽然 fixtures 非常适合静态数据,但对于动态数据生成或更复杂的数据场景,你可能会考虑使用 JavaScript/TypeScript 模块或自定义 Cypress 命令。然而,对于大多数常见的数据驱动测试需求,fixtures 提供了一个优雅且直接的解决方案。