Test Data Management — Fixture / Factory / Seed / Cleanup 完整策略
自動化測試最大坑:test data 管理。Fixture vs Factory vs Mother、Seed 策略、cleanup 模式、跨環境資料、敏感資料處理。附 pytest / Playwright 範例。
💡 本文原刊於 qa.9niche.com,2026-08 併入 9niche.com 懶人包,內容照原文完整搬遷。
目錄
1. 前言
「自動化測試跑兩個禮拜後 staging DB 變垃圾場」是 99% 團隊的痛。Test data 管理沒做好、自動化壽命 = 半年。這篇給你 6 種策略 + 完整實作。
2. 為什麼 Test Data 是頭號殺手
Test data 不管理 = flaky test → 不信任 → 棄置。
3. 6 種 Test Data 策略
每種有適合的場景。
4. 策略 1: Fixture — 靜態檔案
適合:固定的 reference data(國家清單、產品分類)。
# tests/fixtures/users.yml
users:
- id: 1
email: [email protected]
role: admin
- id: 2
email: [email protected]
role: user
# pytest
@pytest.fixture
def users(scope="session"):
with open('tests/fixtures/users.yml') as f:
return yaml.safe_load(f)['users']
def test_admin_can_see_panel(users):
admin = users[0]
# ...
問題:多 test 共用 → 改一個壞一票。
5. 策略 2: Factory — 動態產生(最強)
適合:每 test 新建獨立資料、避免共用衝突。
Python 用 factory_boy
# tests/factories.py
import factory
from app.models import User, Order
class UserFactory(factory.Factory):
class Meta:
model = User
email = factory.Sequence(lambda n: f"qa-user-{n}@test.com")
name = factory.Faker('name')
role = "user"
created_at = factory.LazyFunction(datetime.now)
class OrderFactory(factory.Factory):
class Meta:
model = Order
user = factory.SubFactory(UserFactory)
total = factory.Faker('pydecimal', positive=True, max_value=1000)
status = "pending"
# test
def test_user_can_view_own_order():
user = UserFactory()
order = OrderFactory(user=user)
# ...
def test_admin_view_all_orders():
# 一行建 10 個 user 各 3 個 order
users = UserFactory.create_batch(10)
for u in users:
OrderFactory.create_batch(3, user=u)
Playwright 也可以
// fixtures/factories.ts
import { faker } from '@faker-js/faker';
let userIdSeq = 0;
export function makeUser(overrides = {}) {
userIdSeq++;
return {
email: `qa-user-${userIdSeq}-${Date.now()}@test.com`,
name: faker.person.fullName(),
role: 'user',
...overrides,
};
}
export function makeOrder(user, overrides = {}) {
return {
user_id: user.id,
total: faker.number.float({ min: 10, max: 1000, precision: 0.01 }),
status: 'pending',
...overrides,
};
}
test('user views own order', async ({ api, page }) => {
const user = await api.post('/users', makeUser()).json();
const order = await api.post('/orders', makeOrder(user)).json();
// ...
});
關鍵:每個 test 自己的 user/data、不互打。
6. 策略 3: Seed Script — DB 初始
適合:dev / staging 環境的 reference data + 少量 sample data。
# 跑一次塞滿基本資料
npm run db:seed
# 或
python manage.py seed_test_data
# seeds/dev_seed.py
def seed():
# Reference data
Country.objects.bulk_create([
Country(code='TW', name='台灣'),
Country(code='JP', name='日本'),
])
# Sample users
for i in range(20):
UserFactory(email=f'demo-{i}@example.com')
# Sample orders
OrderFactory.create_batch(100)
問題:Seed 只能跑一次、跑多次會重複。要設計成 idempotent。
7. 策略 4: Snapshot — Prod 抽樣(謹慎用)
適合:整合測試需要真實 data 結構與分佈。
必須去識別化的欄位
- ✅ 姓名 → faker
- ✅ Email →
user_{id}@masked.com - ✅ 手機 / 身分證 → fake
- ✅ 信用卡 → mask 中間 8 位
- ✅ 地址 → fake
- ✅ IP → 隨機
工具
- pgreplay (PostgreSQL)
- AWS DMS(雲端)
- 自建 script + Faker library
8. 策略 5: On-the-fly via API — 最真實
適合:E2E test、要走真實 flow。
test('register → verify email → login', async ({ page, api }) => {
// 1. API 建 user (跟前端 register flow 一樣)
const email = `qa-${Date.now()}@test.com`;
await api.post('/auth/register', { email, password: 'Pass@123' });
// 2. 從 mail server 拿 verification link
const link = await getVerificationLink(email);
// 3. 走 verify
await page.goto(link);
// 4. Login
await page.goto('/login');
await page.fill('[name=email]', email);
await page.fill('[name=password]', 'Pass@123');
await page.click('[type=submit]');
// 5. Assert
await expect(page).toHaveURL('/dashboard');
});
最真實、最慢。適合 critical flow。
9. 策略 6: Shared / Singleton — 共用一份(慎用)
適合:read-only 的 fixture(產品目錄)。
@pytest.fixture(scope='session')
def all_countries(db):
# 整 session 只建一次
return CountryFactory.create_batch(50)
禁忌:可改寫的資料絕對不要 session scope。
10. 命名規範(避免 prod data 跟 test data 混)
# ✅ 一眼看出是測試
email = f'qa-test-{uuid.uuid4()}@example.com'
name = f'QA_Test_User_{uuid.uuid4()}'
# ❌ 看起來像真用戶
email = '[email protected]'
name = 'Alice Chen'
好處:
- 後台搜
qa-test-一次 cleanup - Customer support 不會誤打給測試 email
- Analytics 可以排除測試流量
11. Cleanup 策略
Strategy A: 每 test cleanup(pytest fixture)
@pytest.fixture
def fresh_user(api):
user = api.post('/users', json=make_user()).json()
yield user
# Test 跑完自動清
api.delete(f'/users/{user["id"]}')
問題:test fail 時 cleanup 也跑 → 看不到失敗瞬間的 data。
# 改成失敗時保留
@pytest.fixture
def fresh_user(api, request):
user = api.post('/users', json=make_user()).json()
yield user
if request.node.rep_call.passed:
api.delete(f'/users/{user["id"]}')
else:
print(f"⚠️ Keeping user {user['id']} for debugging")
Strategy B: Transactional(最乾淨)
@pytest.fixture
def db_session():
connection = engine.connect()
transaction = connection.begin()
session = Session(bind=connection)
yield session
session.close()
transaction.rollback() # 一切都不留
connection.close()
所有改動都 rollback。最乾淨。但 API 測試 / E2E 用不了(API 走 HTTP、不在同 transaction)。
Strategy C: 整 DB reset(CI 友善)
# CI 起 docker-compose 含 fresh DB
docker compose up -d db
python manage.py migrate
python manage.py seed_dev_data
npm run test:e2e
每次 CI 全新 DB → 0 污染。慢一點但乾淨。
Strategy D: Nightly cron
-- 每晚 3am 清測試 user
DELETE FROM users WHERE email LIKE 'qa-test-%' AND created_at < NOW() - INTERVAL '24 hours';
備胎策略。
12. 跨環境的 Test Data 策略
規則:
- Local 用 seed + factory
- CI 用 fresh container
- Staging 用 anonymized prod snapshot
- Prod 絕對不寫測試資料
13. 敏感資料處理
Faker 範例
from faker import Faker
fake = Faker('zh_TW')
email = fake.email() # [email protected]
name = fake.name() # 王小明
address = fake.address() # 台北市信義區...
phone = fake.phone_number() # 0912345678
ssn = fake.ssn() # 假身分證
cc = fake.credit_card_number() # 4242 4242 4242 4242
14. 測試卡號(信用卡測試專用)
Visa: 4111 1111 1111 1111
Visa (Stripe): 4242 4242 4242 4242
Mastercard: 5555 5555 5555 4444
Amex: 3782 822463 10005
過期卡: 4000 0000 0000 0069
扣款失敗: 4000 0000 0000 0002
3DS 必驗: 4000 0000 0000 3220
15. 反模式
16. 工具地圖
| 工具 | 用途 | 語言 |
|---|---|---|
| factory_boy | Python factory | Python |
| Faker | 假資料 generator | Multi |
| Mockaroo | 線上產假資料 | Web |
| fishery | TS factory | TypeScript |
| factories.ts 手寫 | TS 手刻 | TypeScript |
| Test Containers | Docker 起測試 DB | Multi |
| db-fixtures | Django fixture | Python |
| factory-girl (TS) | TS factory | TypeScript |
17. QA Lead 該推的 3 件事
- Test data 規範寫進 onboarding(每個新 QA 進來都讀)
- Cleanup strategy 跟 dev 對齊(DB schema 改了 fixture 也要改)
- Test data dashboard — 多少測試 user / 還在 DB 多少(看健康)
18. 給 QA 的 5 句
- 第一週做 test data 規範、後面省 6 個月維護
- 用 factory > fixture > snapshot > shared
- 命名加 prefix(qa-test-)救你的人生
- 失敗時別 cleanup、好用
- 永遠不要在 prod 寫 test data
19. 最後
Test data 是自動化的隱形主角。寫得好沒人看見、寫不好整個 team 都受害。從今天起把所有 test data 加 qa-test- prefix、每個 test 自己的 factory、cleanup 寫進 fixture — 三個月後你的自動化會從「2 週後不能跑」變「3 年後還在跑」。
相關連結
Flaky test 不能用 retry 蓋住。系統化的 reproduce → isolate → diagnose → fix → prevent,含 race condition / timing / 環境污染常見 root cause。
從零搭起 API 測試框架。pytest fixtures、requests session、JSON schema 驗證、auth 處理、CI 整合,附完整範例。
給「會寫 test 但不懂 CI/CD」的 QA 看的入門。Pipeline 七階段、QA 在每一階段做什麼、quality gate 怎麼設、常見坑。
相關懶人包
2026 QA 趨勢實戰:我看到的 5 個轉變(AI、Shift-Left、Observability)
從手動 QA 到 AI 輔助、從測試金字塔到測試獎盃。這篇分享我這 10+ 年看 QA 從「測完才知道」到「shift-left + AI」的真實觀察。
AI / LLM 功能 Spec Review — 幻覺 / 評估 / 成本 / 法遵 8 個必問
AI 功能 spec review 完整指南。LLM 不確定性處理、評估指標、Prompt versioning、成本控制、安全護欄、法遵(EU AI Act / GDPR)、Fallback、人工 review 流程。
AI Agent 系統測試 — 自主執行 / 工具呼叫 / 多步推理的 QA 策略
測試 AI Agent 完整方法。Tool calling 驗證、Trajectory 評估、Failure mode 分類、無限迴圈防止、成本上限、安全 sandbox、Multi-agent 協作測試。
一般聲明
本站提供之資訊僅供參考,不保證其完整性與正確性。使用者應自行判斷資訊之適用性。