獨孤九劍的「破鞭式」,針對的是鞭子的軟性特性,破解的關鍵在於利用鞭子的柔軟,避開其尖銳或硬點,並利用其彈性進行反制,讓對方無法有效地攻擊,甚至可能被鞭子自身的力量所傷。在自動化測試領域,也有一種類似鞭子的設計模式,一串接著一串,透過串鏈的方式呼叫,提高程式碼的閱讀。
Fluent / Chain of Invocations 是在測試設計模式中,讓測試程式碼能夠透過方法串鏈呼叫(method chaining)的方式,讓動作與斷言像自然語言一樣連貫閱讀的技巧。它的目的主要有三個:
在撰寫測試程式碼需要建立某個物件前,可能會需要建立其他物件或是使用者的必須一系列的操作才能完成某個行為,使用 Fluent Pattern 我們可以將有關的操作行為連繫起來。
import { test, expect } from '@playwright/test';
test('使用正確帳號密碼能成功登入', async ({ page }) => {
// Step 1: 前往登入頁
await page.goto('https://your-app.example.com/login');
// Step 2: 輸入帳號
const usernameInput = page.getByTestId('login-username');
await usernameInput.fill('user01');
// Step 3: 輸入密碼
const passwordInput = page.getByTestId('login-password');
await passwordInput.fill('pass123');
// Step 4: 提交表單
const submitButton = page.getByTestId('login-submit');
await submitButton.click();
// Step 5: 驗證登入成功
await expect(page).toHaveURL('https://your-app.example.com/home');
await expect(page.getByTestId('user-avatar')).toBeVisible();
});
在這段程式碼裡,使用者動作與驗證分開,每一步都要重新呼叫元素。
import { test } from '@playwright/test';
import { LoginPage } from '../page-objects/LoginPage';
test('使用 Fluent API 登入成功', async ({ page }) => {
const login = new LoginPage(page);
await login
.goto('https://your-app.example.com/login')
.enterUsername('user01')
.enterPassword('pass123')
.clickLoginButton()
.shouldSeeHomePage();
});
Fluent Pattern,簡單來說,就是讓一個方法在執行完畢後,回傳它自身的物件。這樣做的好處是,你可以把一連串的動作串聯起來,讓測試程式碼讀起來更像是在描述一個流暢的行為。因此可以增加可讀性:將多個獨立的步驟,串聯成一個語意化的「行為」。當然也可以增加維護性:當你使用這個模式,所有的 UI 元素選取器和等待策略都會集中在 Page Object 裡面。如果今天頁面上的某個按鈕換了 ID,你只需要在一個地方修改,所有使用這個方法的測試案例都不需要更改,大大降低了維護成本。
另外就是可以重複被呼叫,你可以將常用的行為封裝成可重複使用的鏈式方法。例如,一個 loginAs(user) 的方法可以在所有需要登入的測試中重複使用,不需要每次都重新寫一次登入的邏輯。
即便 Fluent Pattern 很方便,但在使用時,還是要掌握一些原則,才不會讓程式碼變得難以管理。避免過度抽象化:雖然你可以把所有動作都串聯起來,但要確保這個方法鏈不會太長、太複雜,否則程式碼會變得難以閱讀和理解。適度的抽象化能提高效率,但過度抽象則會適得其反。避免重複等待:Playwright 本身就具備強大的**自動等待(Auto-Waiting)**功能。當你在進行操作時,它會自動等到元素準備好才繼續。因此,大部分時候,你不需要額外使用 page.waitForSelector 或 page.waitForTimeout。如果你的測試中充滿了這些手動等待,通常代表你的測試腳本設計得不夠好,會導致測試不穩定。
Fluent 讓測試案例能夠專注「描述行為」,把 UI 細節封裝到 Page Object 中。對中大型專案而言,它能顯著降低 selector 漂移帶來的維護成本,並提升報告與流程表達力;但在教學或一次性實驗時,非 Fluent 仍然直觀且成本更低。選擇取決於規模、穩定性與協作需求。