獨孤九劍的「破刀式」是一招破解單刀(在單刀中又有快刀法)、雙刀、柳葉刀、鬼頭刀、大砍刀、斬馬刀等種種刀法。昨天,講到 POM ,但其實隨著網頁越來越複雜,單一網頁可能會產生多個 Page Object,造成管理上的困難,今天我想要介紹 POM 的另外一種變體,Page Factory 用來解決 POM 在建立時的維護成本。
Page Factory 是 Page Object Model(POM)的一種進階變體,主要解決 POM 類別建立與維護上的重複與手動管理成本。它的核心思想是:由一個統一的工廠類別(Factory)負責建立、管理並回傳所需的 Page Object 實例,而不是在每個測試檔案中手動 new 一個頁面物件。
雖然 POM 能提高可維護性,但當專案頁面越多時,會出現一些痛點:
使用 Page Factory 透過集中化管理,可以幫助我們:
在下面這個例子,我們主要會有首頁和登入頁面兩個 Page Object 類別:
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test';
export class LoginPage {
constructor(private page: Page) {}
usernameInput = this.page.getByTestId('login-username');
passwordInput = this.page.getByTestId('login-password');
submitButton = this.page.getByTestId('login-submit');
async goto() {
await this.page.goto('https://your-app.example.com/login');
}
async login(username: string, password: string) {
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}
// pages/HomePage.ts
import { Page } from '@playwright/test';
export class HomePage {
constructor(private page: Page) {}
async isLoaded() {
return this.page.getByRole('heading', { name: '首頁' }).isVisible();
}
}
// pages/PageFactory.ts
import { Page } from '@playwright/test';
import { LoginPage } from './LoginPage';
import { HomePage } from './HomePage';
export class PageFactory {
constructor(private page: Page) {}
loginPage() {
return new LoginPage(this.page);
}
homePage() {
return new HomePage(this.page);
}
}
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { PageFactory } from '../pages/PageFactory';
test('使用者可以成功登入並進入首頁', async ({ page }) => {
const factory = new PageFactory(page);
const loginPage = factory.loginPage();
await loginPage.goto();
await loginPage.login('user01', 'pass123');
const homePage = factory.homePage();
expect(await homePage.isLoaded()).toBeTruthy();
});
使用 Page Factory 的優點
一個好的命名能讓程式碼更具可讀性。對於 Page Factory,你可以給它一個清晰的名字,例如 PageObjectManager 或 PageFactory。而其內部的方法也應該語意化,清楚表達其所回傳的頁面物件,例如:getLoginPage()、getHomePage()。
單一職責原則 (SRP) 是 Page Factory 的核心。它唯一的職責就是「建立與管理」頁面物件。它不應該包含任何與測試邏輯、驗證 (Assertion) 或是資料處理相關的程式碼。將這些邏輯分開,能確保你的測試架構清晰、易於維護。
可以透過我們在第九天學到的 Fixtures,來提供 Page Factory 的實例。這樣一來,你的測試案例就不需要手動 new 出一個工廠,而是可以直接從 fixture 中取得,讓程式碼更乾淨、更具彈性。
Page Factory 是一種進階版的 Page Object Model (POM),主要用來解決當網頁數量與複雜度增加時,由 POM 衍生的管理問題。
如果說 POM 是將雜亂的程式碼抽象化,那 Page Factory 則是將 Page Object 類別的實例化過程集中管理。它就像一個統一的工廠,負責建立並回傳所需的頁面物件,讓測試案例可以直接向它索取,而不需要手動創建,這大大降低了開發與維護成本。透過 Page Factory,我們的測試程式碼會更乾淨、更專注於測試邏輯本身,並且與 Page Object 的細節解耦。這個模式提高了程式碼的可讀性和擴充性。當需要新增或替換頁面時,只需在 Factory 類別中調整,就能避免影響到其他測試案例。
將 Page Factory 與 Fixtures 結合,能進一步提升效率。我們可以透過 Fixture 在每個測試開始前,自動建立一個 Page Factory 實例,確保每個測試都能在一致且穩定的環境中執行。簡單的說,掌握了 Page Factory,你便不再需要為了管理頁面物件而煩惱,而是能將精力專注於核心測試邏輯。它能讓你的測試程式碼更為簡潔、更有力。