Skip to main content

参数化测试

介绍

¥Introduction

你可以在测试级别或项目级别参数化测试。

¥You can either parameterize tests on a test level or on a project level.

参数化测试

¥Parameterized Tests

example.spec.ts
[
{ name: 'Alice', expected: 'Hello, Alice!' },
{ name: 'Bob', expected: 'Hello, Bob!' },
{ name: 'Charlie', expected: 'Hello, Charlie!' },
].forEach(({ name, expected }) => {
// You can also do it with test.describe() or with multiple tests as long the test name is unique.
test(`testing with ${name}`, async ({ page }) => {
await page.goto(`https://example.com/greet?name=${name}`);
await expect(page.getByRole('heading')).toHaveText(expected);
});
});

钩子前后

¥Before and after hooks

大多数情况下,你应该将 beforeEachbeforeAllafterEachafterAll 钩子放在 forEach 之外,这样钩子只会执行一次:

¥Most of the time you should put beforeEach, beforeAll, afterEach and afterAll hooks outside of forEach, so that hooks are executed just once:

example.spec.ts
test.beforeEach(async ({ page }) => {
// ...
});

test.afterEach(async ({ page }) => {
// ...
});

[
{ name: 'Alice', expected: 'Hello, Alice!' },
{ name: 'Bob', expected: 'Hello, Bob!' },
{ name: 'Charlie', expected: 'Hello, Charlie!' },
].forEach(({ name, expected }) => {
test(`testing with ${name}`, async ({ page }) => {
await page.goto(`https://example.com/greet?name=${name}`);
await expect(page.getByRole('heading')).toHaveText(expected);
});
});

如果你希望每个测试都有钩子,你可以将它们放在 describe() 中 - 因此它们会在每次迭代/每个单独的测试中执行:

¥If you want to have hooks for each test, you can put them inside a describe() - so they are executed for each iteration / each individual test:

example.spec.ts
[
{ name: 'Alice', expected: 'Hello, Alice!' },
{ name: 'Bob', expected: 'Hello, Bob!' },
{ name: 'Charlie', expected: 'Hello, Charlie!' },
].forEach(({ name, expected }) => {
test.describe(() => {
test.beforeEach(async ({ page }) => {
await page.goto(`https://example.com/greet?name=${name}`);
});
test(`testing with ${expected}`, async ({ page }) => {
await expect(page.getByRole('heading')).toHaveText(expected);
});
});
});

参数化项目

¥Parameterized Projects

Playwright Test 支持同时运行多个测试项目。在下面的示例中,我们将运行两个具有不同选项的项目。

¥Playwright Test supports running multiple test projects at the same time. In the following example, we'll run two projects with different options.

我们声明选项 person 并在配置中设置该值。第一个项目以值 Alice 运行,第二个项目以值 Bob 运行。

¥We declare the option person and set the value in the config. The first project runs with the value Alice and the second with the value Bob.

my-test.ts
import { test as base } from '@playwright/test';

export type TestOptions = {
person: string;
};

export const test = base.extend<TestOptions>({
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],
});

我们可以在测试中使用该选项,与 fixtures 类似。

¥We can use this option in the test, similarly to fixtures.

example.spec.ts
import { test } from './my-test';

test('test 1', async ({ page, person }) => {
await page.goto(`/index.html`);
await expect(page.locator('#node')).toContainText(person);
// ...
});

现在,我们可以使用项目在多种配置中运行测试。

¥Now, we can run tests in multiple configurations by using projects.

playwright.config.ts
import { defineConfig } from '@playwright/test';
import type { TestOptions } from './my-test';

export default defineConfig<TestOptions>({
projects: [
{
name: 'alice',
use: { person: 'Alice' },
},
{
name: 'bob',
use: { person: 'Bob' },
},
]
});

我们还可以在夹具中使用该选项。了解有关 fixtures 的更多信息。

¥We can also use the option in a fixture. Learn more about fixtures.

my-test.ts
import { test as base } from '@playwright/test';

export type TestOptions = {
person: string;
};

export const test = base.extend<TestOptions>({
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],

// Override default "page" fixture.
page: async ({ page, person }, use) => {
await page.goto('/chat');
// We use "person" parameter as a "name" for the chat room.
await page.getByLabel('User Name').fill(person);
await page.getByText('Enter chat room').click();
// Each test will get a "page" that already has the person name.
await use(page);
},
});
注意

参数化项目行为在版本 1.18 中已更改。了解更多

¥Parameterized projects behavior has changed in version 1.18. Learn more.

传递环境变量

¥Passing Environment Variables

你可以使用环境变量从命令行配置测试。

¥You can use environment variables to configure tests from the command line.

例如,考虑以下需要用户名和密码的测试文件。通常最好不要将密钥存储在源代码中,因此我们需要一种从外部传递密钥的方法。

¥For example, consider the following test file that needs a username and a password. It is usually a good idea not to store your secrets in the source code, so we'll need a way to pass secrets from outside.

example.spec.ts
test(`example test`, async ({ page }) => {
// ...
await page.getByLabel('User Name').fill(process.env.USER_NAME);
await page.getByLabel('Password').fill(process.env.PASSWORD);
});

你可以使用在命令行中设置的秘密用户名和密码来运行此测试。

¥You can run this test with your secret username and password set in the command line.

USER_NAME=me PASSWORD=secret npx playwright test

同样,配置文件也可以读取通过命令行传递的环境变量。

¥Similarly, configuration file can also read environment variables passed through the command line.

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
});

现在,你可以针对临时或生产环境运行测试:

¥Now, you can run tests against a staging or a production environment:

STAGING=1 npx playwright test

.env 文件

¥.env files

为了使环境变量更易于管理,请考虑诸如 .env 文件之类的内容。下面是使用 dotenv 包直接在配置文件中读取环境变量的例子。

¥To make environment variables easier to manage, consider something like .env files. Here is an example that uses dotenv package to read environment variables directly in the configuration file.

playwright.config.ts
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';
import path from 'path';

// Read from ".env" file.
dotenv.config({ path: path.resolve(__dirname, '.env') });

// Alternatively, read from "../my.env" file.
dotenv.config({ path: path.resolve(__dirname, '..', 'my.env') });

export default defineConfig({
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
});

现在,你只需编辑 .env 文件即可设置你想要的任何变量。

¥Now, you can just edit .env file to set any variables you'd like.

# .env file
STAGING=0
USER_NAME=me
PASSWORD=secret

像往常一样运行测试,你的环境变量应该被选取。

¥Run tests as usual, your environment variables should be picked up.

npx playwright test

通过 CSV 文件创建测试

¥Create tests via a CSV file

Playwright 测试运行程序在 Node.js 中运行,这意味着你可以直接从文件系统读取文件并使用你首选的 CSV 库解析它们。

¥The Playwright test-runner runs in Node.js, this means you can directly read files from the file system and parse them with your preferred CSV library.

例如,请参阅此 CSV 文件,在我们的示例 input.csv 中:

¥See for example this CSV file, in our example input.csv:

"test_case","some_value","some_other_value"
"value 1","value 11","foobar1"
"value 2","value 22","foobar21"
"value 3","value 33","foobar321"
"value 4","value 44","foobar4321"

在此基础上,我们将使用 NPM 中的 csv-parse 库生成一些测试:

¥Based on this we'll generate some tests by using the csv-parse library from NPM:

test.spec.ts
import fs from 'fs';
import path from 'path';
import { test } from '@playwright/test';
import { parse } from 'csv-parse/sync';

const records = parse(fs.readFileSync(path.join(__dirname, 'input.csv')), {
columns: true,
skip_empty_lines: true
});

for (const record of records) {
test(`foo: ${record.test_case}`, async ({ page }) => {
console.log(record.test_case, record.some_value, record.some_other_value);
});
}