跳到主要內容
wen aidev

現代軟體測試與 AI 實戰 (5):AI 輔助整合測試實戰,從 Markdown 到真實程式碼

8 分鐘po-wen

有了 AI 生成的純文字測試情境後,我們該如何優雅地將它們實作為真正的「整合測試程式碼」?本篇示範如何透過 Cursor IDE 配合 Testcontainers 把自動化測試實作出來。

目錄

系列文章地圖

點節點可以直接跳到那一篇。

上一篇文章中,我們成功讓 AI 扮演 QA 角色,從需求文件中產出了一份無死角的 Markdown 測試案例清單(Test Cases)。

但純文字終究只是理想,真正能把關品質的還是「實作出來的程式碼」。過去,要寫一支完整的整合測試(包含起 DB、建資料、發 Request、清除資料)非常痛苦且耗時。現在,我們將示範如何讓 Cursor / Claude Code 自動完成這最後的實作步驟。


理論落地:讓 AI 為你寫測試框架

AI 產生整合測試時,會把 test-cases.md 的情境、專案現有的程式碼與你指定的測試框架(例如 Testcontainers)組成一支可執行的測試檔。

整合測試 · 三份輸入的來源地圖
1
讀測試情境
AI 讀 test-cases.md,每個情境寫成一個測試,名稱照「方法名_測試情境_預期結果」。
2
讀業務邏輯
AI 參考 LoginService 的實作,知道要 import 哪個函式、怎麼呼叫。
3
套框架設定
依你指定的 Testcontainers,beforeAll 啟動 PostgreSQL 容器並建 schema 與 Seed Data,afterAll 銷毀容器。
4
執行 npm test
確認套件已安裝後執行 npm test,不依賴外部 Staging 環境。
讀進的輸入 1/3寫出的程式行 1通過的測試 0/2
AI 讀的輸入
test-cases.md
上一篇產出的測試情境
LoginService.ts
專案現有的業務邏輯
Testcontainers 設定
你指定的測試框架
$ npm test
… 等待Login_ValidCredentials_ReturnsJwtToken
… 等待Login_FailFiveTimes_AccountIsLocked
login.integration.test.ts
1import { PostgreSqlContainer } from '@testcontainers/postgresql';
2import { loginUser } from '../services/LoginService';
3beforeAll(async () => {
4 container = await new PostgreSqlContainer('postgres:15-alpine').start();
5 await dbClient.query(`CREATE TABLE users (...)`);
6 await dbClient.query(`INSERT INTO users ... 'test@example.com' ...`);
7}, 60000);
8afterAll(async () => { await dbClient.end(); await container.stop(); });
9test('Login_ValidCredentials_ReturnsJwtToken', async () => {
10 const result = await loginUser('test@example.com', 'correctPassword', dbClient);
11 expect(result.status).toBe(200);
12});
13test('Login_FailFiveTimes_AccountIsLocked', async () => {
14 await loginUser('test@example.com', 'wrongPassword', dbClient); // ×5
15 expect(result.status).toBe(423); // 423 Locked
16});
情境決定要測什麼

前置需求:安裝 Docker

🐳 開始前先確認 Docker 已安裝

Testcontainers 底層依賴 Docker,請先安裝

Docker Desktop

(Windows / Mac)或 Docker Engine(Linux)。

安裝完成後,在終端機確認 Docker 正在運行:
docker ps

看到空的容器列表(不是 error)就代表 Docker 已就緒。

✅ 不需要自己 docker run 任何東西,Testcontainers 會幫你全自動處理。

準備強大的測試基礎設施

在我們請 AI 寫 Code 之前,我們必須先為專案引入正確的測試框架。為了避免第三篇文章提到的「環境迷思」(例如連錯 Staging DB 導致資料污染),我們強烈推薦使用 Testcontainers 技術。

什麼是 Testcontainers? 這是一個讓開發者可以在程式碼中直接用 Docker 啟動臨時資料庫(如 PostgreSQL、Redis)的函式庫。測試開始時啟動(乾淨的空資料庫),測試結束時容器就會自動被銷毀,絕不會有髒資料殘留。

依你的語言安裝對應套件:

# Node.js / TypeScript 專案
npm install --save-dev testcontainers @testcontainers/postgresql

# C# / .NET 專案
dotnet add package Testcontainers.PostgreSql

# Python 專案
pip install testcontainers[postgres]

步驟實戰:在 Cursor 中下達指令

打開 Cursor 的 Agent 面板(Ctrl + I 或 Cmd + I),選中我們在上一篇產出的 @test-cases.md 與你的核心業務邏輯檔案(例如 @LoginController.cs 或 @login.ts),然後給出以下 Prompt:

🚀 整合測試實作提示詞模板

我需要為登入 API 撰寫整合測試。
請閱讀 @test-cases.md 中的所有情境,並參考 @LoginController 的實作邏輯。

請幫我產出測試檔案,並遵循以下規範:

1. 請使用 (xUnit / Jest / pytest,依你的專案填寫)。
2. 必須使用 Testcontainers 啟動一個全新的 PostgreSQL 實例,作為測試環境資料庫。
3. 每個測試執行前 (Setup),請插入必要的假資料 (Seed Data);執行後 (Teardown) 確保資源獨立。
4. 測試命名請使用「方法名_測試情境_預期結果」的格式。

請直接實作所有 Happy Path 與 Negative Cases 的程式碼。

AI 實際生成的程式碼長什麼樣

不到 30 秒,Cursor 會一口氣幫你生成完整的測試檔。以下是 Node.js + PostgreSQL 的典型輸出結果(你的 AI 也會產出類似的程式碼):

// login.integration.test.ts
// 由 Cursor 根據 test-cases.md + LoginService.ts 自動生成

import {
  PostgreSqlContainer,
  StartedPostgreSqlContainer,
} from '@testcontainers/postgresql';
import { Client } from 'pg';
import { loginUser } from '../services/LoginService';

let container: StartedPostgreSqlContainer;
let dbClient: Client;

// Setup:測試開始前自動啟動一個全新 PostgreSQL 容器
beforeAll(async () => {
  container = await new PostgreSqlContainer('postgres:15-alpine').start();

  dbClient = new Client({ connectionString: container.getConnectionUri() });
  await dbClient.connect();

  // 建立 schema 與 Seed Data
  await dbClient.query(`
    CREATE TABLE users (
      id SERIAL PRIMARY KEY,
      email TEXT UNIQUE NOT NULL,
      password_hash TEXT NOT NULL,
      failed_attempts INT DEFAULT 0,
      locked_at TIMESTAMPTZ
    )
  `);
  await dbClient.query(`
    INSERT INTO users (email, password_hash)
    VALUES ('test@example.com', '$2b$10$hashedpassword')
  `);
}, 60000); // 等待 Docker pull,給 60 秒

// Teardown:測試結束後銷毀容器,完全不留髒資料
afterAll(async () => {
  await dbClient.end();
  await container.stop();
});

// Happy Path
test('Login_ValidCredentials_ReturnsJwtToken', async () => {
  const result = await loginUser(
    'test@example.com',
    'correctPassword',
    dbClient,
  );
  expect(result.token).toBeDefined();
  expect(result.status).toBe(200);
});

// Negative Case:失敗 5 次鎖定(AI 自動用迴圈寫好)
test('Login_FailFiveTimes_AccountIsLocked', async () => {
  for (let i = 0; i < 5; i++) {
    await loginUser('test@example.com', 'wrongPassword', dbClient);
  }
  const result = await loginUser('test@example.com', 'wrongPassword', dbClient);
  expect(result.status).toBe(423); // 423 Locked
  expect(result.message).toContain('帳號已鎖定');
});

這段程式碼涵蓋了:

  • ✅ Docker 容器的自動啟動與銷毀(beforeAll / afterAll)
  • ✅ Schema 建立 + Seed Data 注入
  • ✅ Happy Path 與 Negative Case 的完整驗證
  • ✅ 不依賴任何外部 Staging 環境,在任何機器上都能執行

你唯一的任務,就是確認套件已安裝(上面的 npm install 步驟),然後按下 npm test,享受滿滿的綠燈。


品質的保證:從開發到部署

透過這兩篇文章的結合,我們已經打通了「從需求、測試案例到整合測試程式碼」的自動化流程。這正是現代軟體工業中「測試左移」與「AI 賦能」的最佳拍檔。

你的開發者不再需要花幾個小時去寫繁瑣的 Setup 程式碼,你的 QA 也可以專注於更抽象層次的探索測試。

AI 的野心卻不僅於此。在系列文章的最終回,我們將進入最高階的應用:Agentic Testing 的閉環。如果 AI 連「自動開啟瀏覽器操作、錄影、遇錯自我修復並發 Issue」都能做到呢?

前往本系列的最終壓軸:Agentic Testing 的閉環:AI 自動執行驗收測試與除錯。

支持作者 ☕

台灣用戶:

透過 LINE Pay 支持

國際用戶:

透過 Ko-fi 支持

相關文章

留言討論

Facebook 留言