Skip to main content

平行處理

簡介

Playwright Test 平行執行測試。為了達到這一點,它會執行多個同時運行的工作程序。預設情況下,測試檔案是平行執行的。單個檔案中的測試會按順序在同一個工作程序中執行。

你可以控制平行工作程序的數量,並在整個測試套件中限制失敗次數以提高效率。

Worker 程序

所有測試都在工作程序中執行。這些程序是作業系統程序,獨立運行,由測試執行器編排。所有工作程序都具有相同的環境,每個都會啟動自己的瀏覽器。

你無法在工作程序之間進行通訊。Playwright Test 會盡可能重複使用單一工作程序以加快測試速度,因此多個測試檔案通常會在單一工作程序中依序執行。

工作程序總是在測試失敗後關閉,以確保後續測試有乾淨的環境。

限制工作程序

你可以透過命令列或在組態設定檔中控制平行工作程序的最大數量。

從命令列:

npx playwright test --workers 4

在組態設定檔中:

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

export default defineConfig({
// 在 CI 上限制工作程序數量,本機使用預設值
workers: process.env.CI ? 2 : undefined,
});

停用平行處理

你可以透過僅允許一個工作程序來停用任何平行處理。在組態設定檔中設定 workers: 1 選項,或向命令列傳遞 --workers=1

npx playwright test --workers=1

平行處理單個檔案中的測試

預設情況下,單個檔案中的測試會按順序執行。如果你在單個檔案中有許多獨立的測試,你可能會想要使用 test.describe.configure() 讓它們平行執行。

請注意,平行測試會在獨立的工作程序中執行,無法共享任何狀態或全域變數。每個測試只會為自己執行所有相關的掛勾,包括 beforeAllafterAll

import { test } from '@playwright/test';

test.describe.configure({ mode: 'parallel' });

test('runs in parallel 1', async ({ page }) => { /* ... */ });
test('runs in parallel 2', async ({ page }) => { /* ... */ });

或者,你可以在組態設定檔中選擇讓所有測試進入這個完全平行模式:

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

export default defineConfig({
fullyParallel: true,
});

你也可以只為幾個專案選擇完全平行模式:

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

export default defineConfig({
// 讓特定專案的所有檔案中的所有測試都平行執行
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
fullyParallel: true,
},
]
});

序列模式

你可以將相互依賴的測試標註為序列執行。如果其中一個序列測試失敗,所有後續測試都會被跳過。群組中的所有測試會一起重試。

note

不建議使用序列模式。通常最好讓你的測試保持隔離,這樣它們可以獨立執行。

import { test, type Page } from '@playwright/test';

// 將整個檔案標註為序列執行。
test.describe.configure({ mode: 'serial' });

let page: Page;

test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});

test.afterAll(async () => {
await page.close();
});

test('runs first', async () => {
await page.goto('https://playwright.dev/');
});

test('runs second', async () => {
await page.getByText('Get Started').click();
});

選擇退出完全平行模式

如果你的組態設定使用 testConfig.fullyParallel 對所有測試套用平行模式,你可能仍然想要使用預設設定執行某些測試。你可以在每個 describe 中覆寫模式:

test.describe('runs in parallel with other describes', () => {
test.describe.configure({ mode: 'default' });
test('in order 1', async ({ page }) => {});
test('in order 2', async ({ page }) => {});
});

在多台機器之間分片測試

Playwright Test 可以分片測試套件,使其能夠在多台機器上執行。請參閱分片指南了解更多詳細資訊。

npx playwright test --shard=2/3

限制失敗並快速失敗

你可以透過設定 maxFailures 組態選項或傳遞 --max-failures 命令列旗標來限制整個測試套件中失敗測試的數量。

當使用「最大失敗次數」設定執行時,Playwright Test 會在達到這個失敗測試數量後停止,並跳過任何尚未執行的測試。這對於避免在損壞的測試套件上浪費資源很有用。

傳遞命令列選項:

npx playwright test --max-failures=10

在組態設定檔中設定:

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

export default defineConfig({
// 在 CI 上限制失敗次數以節省資源
maxFailures: process.env.CI ? 10 : undefined,
});

Worker 索引和平行索引

每個工作程序被分配兩個 ID:一個從 1 開始的唯一工作程序索引,以及一個介於 0workers - 1 之間的平行索引。當工作程序重新啟動(例如在失敗後),新的工作程序會有相同的 parallelIndex 和新的 workerIndex

你可以從環境變數 process.env.TEST_WORKER_INDEXprocess.env.TEST_PARALLEL_INDEX 讀取索引,或透過 testInfo.workerIndextestInfo.parallelIndex 存取它們。

隔離平行工作程序之間的測試資料

你可以利用上面提到的 process.env.TEST_WORKER_INDEXtestInfo.workerIndex 來隔離不同工作程序上執行的測試之間的資料庫使用者資料。所有由工作程序執行的測試會重複使用相同的使用者。

建立 playwright/fixtures.ts 檔案來建立 dbUserName 佈置並在測試資料庫中初始化新使用者。使用 testInfo.workerIndex 來區分工作程序。

playwright/fixtures.ts
import { test as baseTest, expect } from '@playwright/test';
// 匯入專案工具以管理測試資料庫中的使用者。
import { createUserInTestDatabase, deleteUserFromTestDatabase } from './my-db-utils';

export * from '@playwright/test';
export const test = baseTest.extend<{}, { dbUserName: string }>({
// 回傳工作程序唯一的資料庫使用者名稱。
dbUserName: [async ({ }, use) => {
// 使用 workerIndex 作為每個工作程序的唯一識別符。
const userName = `user-${test.info().workerIndex}`;
// 在資料庫中初始化使用者。
await createUserInTestDatabase(userName);
await use(userName);
// 測試完成後清理。
await deleteUserFromTestDatabase(userName);
}, { scope: 'worker' }],
});

現在,每個測試檔案都應該從我們的佈置檔案而不是 @playwright/test 匯入 test

tests/example.spec.ts
// 重要:匯入我們的佈置。
import { test, expect } from '../playwright/fixtures';

test('test', async ({ dbUserName }) => {
// 在測試中使用使用者名稱。
});

控制測試順序

Playwright Test 按照宣告順序執行單個檔案中的測試,除非你平行處理單個檔案中的測試

跨檔案的測試執行順序沒有保證,因為 Playwright Test 預設會平行執行測試檔案。但是,如果你停用平行處理,你可以透過按字母順序命名檔案或使用「測試清單」檔案來控制測試順序。

按字母順序排序測試檔案

當你停用平行測試執行時,Playwright Test 會按字母順序執行測試檔案。你可以使用某種命名慣例來控制測試順序,例如 001-user-signin-flow.spec.ts002-create-new-document.spec.ts 等等。

使用「測試清單」檔案

warning

不建議使用測試清單,僅作為盡力而為的支援。某些功能(如 VS Code Extension 和追蹤)可能無法與測試清單正常運作。

你可以將測試放在多個檔案的輔助函式中。考慮以下範例,其中測試不是直接在檔案中定義,而是在包裝函式中定義。

feature-a.spec.ts
import { test, expect } from '@playwright/test';

export default function createTests() {
test('feature-a example test', async ({ page }) => {
// ... test goes here
});
}

feature-b.spec.ts
import { test, expect } from '@playwright/test';

export default function createTests() {
test.use({ viewport: { width: 500, height: 500 } });

test('feature-b example test', async ({ page }) => {
// ... test goes here
});
}

你可以建立一個測試清單檔案來控制測試順序 - 先執行 feature-b 測試,然後執行 feature-a 測試。請注意每個測試檔案是如何包裝在呼叫定義測試函式的 test.describe() 區塊中的。這樣 test.use() 呼叫只會影響來自單個檔案的測試。

test.list.ts
import { test } from '@playwright/test';
import featureBTests from './feature-b.spec.ts';
import featureATests from './feature-a.spec.ts';

test.describe(featureBTests);
test.describe(featureATests);

現在停用平行執行,將工作程序設為一個,並指定你的測試清單檔案。

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

export default defineConfig({
workers: 1,
testMatch: 'test.list.ts',
});
note

不要直接在輔助檔案中定義你的測試。這可能會導致意外結果,因為你的測試現在依賴於 import/require 語句的順序。相反,將測試包裝在一個函式中,該函式將由測試清單檔案顯式呼叫,如上面的範例所示。