iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
IT 管理

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

第 17天:獨孤九劍的破索式 - 資料驅動測試

  • 分享至 

  • xImage
  •  

接續第 16 天的話題,並不是所有功能都像「破氣式」那樣,只從核心業務邏輯出發。有時,我們還會面對一種基於資料的功能,例如 API 測試。這種時候,我們需要另一種心法來應對,那就是 Data-Driven Testing。

內功心法:什麼是 Data-Driven Testing

Data-Driven Testing(資料驅動測試)是一種透過外部化測試數據來驅動測試邏輯的測試方法。它的核心概念是 測試邏輯與測試資料分離,讓同一組測試程式可以針對不同的資料重複執行,達到高覆蓋率、降低維護成本、提升可擴充性。

為什麼要用 Data-Driven Testing

資料驅動測試(Data-Driven Testing)的核心價值在於將測試邏輯與測試資料分離,這讓我們不必為不同的測試情境重複撰寫程式碼,從根本上解決了程式碼重複的問題。透過這種方式,同一套測試流程能夠應用於多組資料,大幅提升測試覆蓋率,同時也讓測試維護變得更簡單,因為當需要新增或修改測試案例時,我們只需要更新外部的資料檔案,而無需更動任何程式碼。這種設計不僅讓測試腳本更精簡,也為未來的擴充性提供了極大的彈性。

常見資料來源

測試資料的來源其實非常多樣,最簡單也最直觀的,是從 CSV、JSON、Excel 或 YAML 這些靜態檔案中讀取,適合用來管理小型的測試案例。當我們需要處理大量或複雜的資料關係時,我會直接從資料庫中讀取,這能確保測試資料與應用程式使用的資料來源一致。如果測試目標是 Web 服務,那麼透過 API 來動態取得或建立測試資料會更有效率,因為這能模擬真實世界中的資料流。不過你也可以用 AI 來即時生成測試資料,特別是在處理一些難以窮舉的邊界值或隨機組合時,這種方式能大幅提高測試的覆蓋度和效率。

招式演練:測試驅動範例

範例 1:JSON 檔案驅動測試

假設我們的登入測試資料存放在 login-data.json

[
  { "username": "user01", "password": "pass123", "expected": "首頁" },
  { "username": "user02", "password": "wrongpass", "expected": "登入失敗" }
]

測試程式碼:

import { test, expect } from '@playwright/test';
import loginData from './login-data.json';

for (const data of loginData) {
  test(`Login with ${data.username}`, async ({ page }) => {
    await page.goto('https://your-app.example.com/login');
    await page.getByTestId('login-username').fill(data.username);
    await page.getByTestId('login-password').fill(data.password);
    await page.getByTestId('login-submit').click();
    await expect(page.locator(`text=${data.expected}`)).toBeVisible();
  });
}

範例 2:從資料庫取得測試資料

有些情境下,我們需要從資料庫讀取最新的測試資料,例如會員帳號、訂單編號等。
以下示範 PostgreSQL 版本(MySQL、MSSQL 類似):

import { Client } from 'pg';
import { test, expect } from '@playwright/test';

async function getLoginDataFromDB() {
  const client = new Client({
    host: 'localhost',
    port: 5432,
    user: 'db_user',
    password: 'db_password',
    database: 'test_db'
  });
  await client.connect();
  const res = await client.query('SELECT username, password, expected FROM login_test_data');
  await client.end();
  return res.rows;
}

test.describe('DB Data-Driven Login Test', () => {
  let testData;

  test.beforeAll(async () => {
    testData = await getLoginDataFromDB();
  });

  for (const data of testData) {
    test(`Login with ${data.username}`, async ({ page }) => {
      await page.goto('https://your-app.example.com/login');
      await page.fill('#username', data.username);
      await page.fill('#password', data.password);
      await page.click('#submit');
      await expect(page.locator(`text=${data.expected}`)).toBeVisible();
    });
  }
});

範例 3:從 API 動態取得測試資料

當測試資料由後端服務維護時,我們可以直接從 API 取得最新測資。

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

test.describe('API Data-Driven Login Test', () => {
  let loginData;

  test.beforeAll(async ({ request }) => {
    const res = await request.get('https://your-api.example.com/test-data/login');
    loginData = await res.json();
  });

  for (const data of loginData) {
    test(`Login with ${data.username}`, async ({ page }) => {
      await page.goto('https://your-app.example.com/login');
      await page.fill('#username', data.username);
      await page.fill('#password', data.password);
      await page.click('#submit');
      await expect(page.locator(`text=${data.expected}`)).toBeVisible();
    });
  }
});

秘笈傳授:最佳實務

在實作資料驅動測試時,我認為有幾個原則非常重要。首先是資料隔離,我們必須確保每組測試資料都是獨立的,避免測試之間互相依賴,不然會因為測試案例執行的先後順序,而影響測試結果,在測試結束後進行清理資料。其次,為了讓團隊能夠共用測試資料協作,將所有的靜態測試資料放在一個集中的地方,例如:版本控管系統或是資料庫中,這不僅方便使用,也能確保每次測試都能使用相同的測試資料集。

另外,在程式碼中避免寫死測試資料,所有資料都應該從外部檔案或資料庫讀取,這樣才能真正實現測試邏輯與資料的分離。在撰寫測試資料時,我們也不能只專注於正常情境,而是要確保測試資料的多樣性,涵蓋正常值、邊界值、錯誤值,甚至極端值。最後,再將這些測試流程與資料集整合到 CI/CD 流程中,讓不同的測試環境能自動對應到不同的測試資料集。

收功:今日總結

資料驅動測試(Data-Driven Testing)的核心價值在於將測試邏輯與測試資料分離,這讓我們能夠將同一個測試流程,應用於多組不同的資料集,從而快速擴大測試覆蓋率。我發現這種方法特別適合用在表單驗證、API 多參數組合測試,以及所有擁有相同流程但輸入不同的情境。透過結合 JSON、資料庫、API 等多種資料來源,我們不僅讓測試變得更易於維護,也讓它們能夠更靈活、更真實地反映業務需求。


上一篇
第 16 天:獨孤九劍的破氣式 - 行為驅動開發
下一篇
第 18 天:獨孤九式總結 - 可維護的測試程式碼
系列文
Playwright + Test Design + AI Agent:自動化測試實戰20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言