iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
IT 管理

Playwright + Test Design + AI Agent:自動化測試實戰系列 第 15

第 15 天:獨孤九劍的破箭式 - Repository

  • 分享至 

  • xImage
  •  

獨孤九劍的「破箭式」用於破解各種暗器,在面對暗器時,施展破箭式,可以根據暗器的來勢和攻擊方向,以最快的速度、最有效的角度進行反擊,將暗器擊落或化解其威力。但今天要介紹的設計模式跟破箭式就沒有什麼關係,有時,我們必須要建立測試資料或業務資料,但根據不同的測試目的,可能是從 API 建立、或是直接插入至資料庫等等,有沒有一種設計模式,呼叫的人不需要知道資料如何被建立,但仍舊可以建立資料出來。

內功心法:什麼是 Repository Pattern

Repository Pattern(儲存庫模式)是一種抽象化資料存取層(Data Access Layer, DAL)的設計模式,它將資料存取邏輯與業務邏輯分離,讓應用程式不直接操作資料庫或 API,而是透過一個統一的介面(Repository)來存取與操作資料。在自動化測試中,Repository Pattern 可以用來集中管理測試資料的存取與準備,無論資料來源是資料庫、REST API、GraphQL API 或 JSON 檔,都可以透過相同的方式取得。

為什麼要使用 Repository Pattern

  • 降低耦合:測試程式不需知道資料儲存的細節(SQL、API 路徑)。
  • 易於維護:資料存取邏輯集中管理,變更時只需修改 Repository 層。
  • 提高可測性:方便替換成 Mock Repository 進行測試。
  • 資料一致性:多個測試案例可共用相同的資料存取規則。

招式演練:Playwright 測試中的應用情境

假設你有一組測試需要在 UI 測試前建立使用者資料,而測試資料可能來自於

  1. 直接操作資料庫(INSERT SQL)
  2. 呼叫後端 REST API 建立使用者
  3. 從測試資料檔讀取(例如 users.json)

Repository 介面

// repositories/UserRepository.ts
export interface UserRepository {
  createUser(user: { username: string; password: string }): Promise<void>;
  getUser(username: string): Promise<{ username: string; password: string } | null>;
}

PostgreSQL 實作

// repositories/PostgresUserRepository.ts
import { Client } from 'pg';
import { UserRepository } from './UserRepository';

export class PostgresUserRepository implements UserRepository {
  async createUser(user) {
    const client = new Client({
      host: process.env.DB_HOST,
      user: process.env.DB_USER,
      password: process.env.DB_PASS,
      database: process.env.DB_NAME,
    });
    await client.connect();
    await client.query('INSERT INTO users (username, password) VALUES ($1, $2)', 
                       [user.username, user.password]);
    await client.end();
  }

  async getUser(username) {
    const client = new Client({ /* 同上設定 */ });
    await client.connect();
    const res = await client.query('SELECT username, password FROM users WHERE username = $1', [username]);
    await client.end();
    return res.rows[0] || null;
  }
}

API 實作

// repositories/ApiUserRepository.ts
import axios from 'axios';
import { UserRepository } from './UserRepository';

export class ApiUserRepository implements UserRepository {
  async createUser(user) {
    await axios.post(`${process.env.API_BASE_URL}/users`, user);
  }

  async getUser(username) {
    const res = await axios.get(`${process.env.API_BASE_URL}/users/${username}`);
    return res.data;
  }
}

測試案例使用

// tests/user-login.spec.ts
import { test, expect } from '@playwright/test';
import { ApiUserRepository } from '../repositories/ApiUserRepository';

test('使用正確帳密登入成功', async ({ page }) => {
  const repo = new ApiUserRepository();
  const testUser = { username: 'user01', password: 'pass123' };
  
  await repo.createUser(testUser);

  await page.goto('/login');
  await page.getByTestId('login-username').fill(testUser.username);
  await page.getByTestId('login-password').fill(testUser.password);
  await page.getByTestId('login-submit').click();

  await expect(page).toHaveURL(/home/);
});

秘笈傳授:最佳實務

  • 抽象化資料來源:讓測試案例不依賴資料儲存方式。
  • 集中管理資料存取邏輯:所有資料相關操作放在 Repository 層。
  • 方便切換環境:可依據測試環境使用不同 Repository 實作(DB、API、Mock)。
  • 搭配 Fixture 使用:在測試前初始化資料,測試後清理。

收功:今日總結

Repository Pattern 在 Playwright 測試中,可以讓 資料準備與清理更彈性,同時讓 UI 測試專注在操作與驗證,降低對資料存取細節的依賴,提升可維護性與可重用性。


上一篇
第 14 天:獨孤九劍的破掌式 - Strategy
系列文
Playwright + Test Design + AI Agent:自動化測試實戰15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言