参数化测试

简介

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

参数化测试

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 外部,以确保钩子只执行一次。

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() 中,这样它们将在每次迭代/每个单独的测试中执行。

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);
    });
  });
});

参数化项目

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

我们声明了 person 选项,并在配置中设置其值。第一个项目使用值 Alice,第二个项目使用值 Bob。

  • TypeScript

  • JavaScript

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 }],
});
my-test.js
const base = require('@playwright/test');

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

我们可以像使用 【fixture】 一样,在测试中使用这个选项。

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);
  // ...
});

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

  • TypeScript

  • JavaScript

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' },
    },
  ]
});
playwright.config.ts
// @ts-check

module.exports = defineConfig({
  projects: [
    {
      name: 'alice',
      use: { person: 'Alice' },
    },
    {
      name: 'bob',
      use: { person: 'Bob' },
    },
  ]
});

我们也可以在 fixture 中使用该选项。了解更多关于 【fixtures】 的内容。

  • TypeScript

  • JavaScript

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);
  },
});
my-test.js
const base = require('@playwright/test');

exports.test = base.test.extend({
  // 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 版本中,参数化项目的行为发生了变化。【了解更多信息】。

传递环境变量

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

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

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);
});

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

  • Bash

  • PowerShell

  • Batch

USER_NAME=me PASSWORD=secret npx playwright test
$env:USER_NAME=me
$env:PASSWORD=secret
npx playwright test
set USER_NAME=me
set PASSWORD=secret
npx playwright test

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

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

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

现在,您可以针对 staging 或生产环境运行测试:

  • Bash

  • PowerShell

  • Batch

STAGING=1 npx playwright test
$env:STAGING=1
npx playwright test
set STAGING=1
npx playwright test

.env 文件

为了更方便地管理环境变量,您可以考虑使用 .env 文件。以下是一个示例,使用 dotenv 包直接在配置文件中读取环境变量。

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 文件来设置您想要的任何变量。

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

像往常一样运行测试,您的环境变量应该会被自动加载。

npx playwright test

通过 CSV 文件创建测试

Playwright 测试运行器在 Node.js 中运行,这意味着你可以直接从文件系统读取文件,并使用你喜欢的 CSV 库进行解析。

例如,以下是我们示例中的 CSV 文件 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 库生成一些测试:

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);
  });
}