Database Migration 測試:Schema 改了,舊資料會怎樣
#測試策略 #資料庫
Database Migration 測試:Schema 改了,舊資料會怎樣 目錄 1. 那個只影響老用戶的 bug 2. Migration 測試在解什麼問題 3. 三種必測的 Migration 情境 4. Rollback 的測試 5. 結尾 那個只影響老用戶的 bug 根據 Redgate 的《State of Database DevOps》報告,超過半數的正式環境事故與資料庫變更有關,而其中最難在測試階段抓到的,往往不是 Migration 腳本本身出錯,而是 Migration 後舊資料在新 Schema 下的行為改變。這正是讓 QA 最容易踩坑的地方——因為功能測試通常只測新路徑,不測老用戶的歷史資料。 我們的 App 有一次 Schema migration:把 users 表的 subscription type 欄位從 ENUM('free', 'pro') 改成 ENUM('free', 'pro', 'enterprise'),同時把所有現有的 pro 用戶資料保持不變。 Migration 在 staging 跑完,沒有問題。上線。 上線一個小時後,客服開始收到老用戶的投訴:「我是 Pro 用戶,但 App 說我是免費版。」 查 log:那些用戶的 subscription type 資料是正確的(值是 pro),但 App 讀取到的卻是 free。 根本原因:App 的後端程式碼有一個地方用了硬編碼的 ENUM index 來判斷訂閱類型——if subscription type index == 1: is pro。ENUM 加了新值之後,index 的對應關係改變了,pro 的 index 從 1 變成 1(沒有變),但程式碼裡另一個地方用 index 0 當 free、index 1 當 pro,加了 enterprise 之後這個映射壞掉了。 Migration 沒有問題,是 Migration 之後的程式碼和舊的 ENUM 假設不相容。 這個 bug 只影響有特定程式碼路徑的舊用戶,新用戶不受影響,所以功能測試沒有發現。 Migration 測試在解什麼問題 Database migration 的測試有兩個維度: 1. Migration 本身是否正確 Schema 改動後,資料是否被正確轉換?Index 是否被正確建立?Constraint 是否被正確加入? 這通常 DBA 或 RD 會驗證,但 QA 要確認的是:「Migration 後,系統的行為是否符合預期?」 2. 舊資料在新 Schema 下的行為 這是最容易被忽略的:Migration 之前存在的資料,在新 Schema 下是否仍然被正確處理? 新功能測試只測新的用戶路徑,但上線後面對的是有各種歷史狀態的老用戶。他們的資料可能在 migration 前就有各種邊界值,這些在功能測試中不會出現。 三種必測的 Migration 情境 情境一:Migration 前後的資料讀取 測試:Migration 執行前後,讀取同一筆資料,結果是否一致? 具體做法: 1. 在 staging 建立一批測試資料,覆蓋所有可能的舊格式 2. 執行 Migration 3. 讀取這批資料,確認值沒有意外改變 特別注意:NULL 值、空字串、邊界值(最大整數、最長字串)在 Migration 後的行為。 情境二:新舊程式碼的相容性 如果 Migration 是 backward compatible(新舊 schema 都能讀),要測試舊版 App client 在新 schema 下的行為。 這個情境在 Mobile 特別重要:App 版本更新後,有用戶還在用舊版 App,他們的舊版 client 會遇到新的 DB schema。根據 App 市場的通用觀察,新版本發布後的 30 天內,通常仍有 15–25% 的活躍用戶使用上一個大版本——這些用戶的舊版 client 和新 schema 的相容性,是 migration 測試不能跳過的環節。 測試方法:在測試環境保留一個舊版 App build,執行 Migration 後,用舊版 App 測試基本功能。 情境三:Migration 中途的行為(Zero downtime migration) 對於不能停機的 production 環境,migration 是逐步進行的。在 migration 進行中,新舊兩個版本的 schema 同時存在。 這個「中間狀態」期間的系統行為需要特別測試: 同時有讀寫的情況下,資料是否一致 如果 migration 卡住或失敗,系統是否能繼續正常運作 Rollback 的測試 Migration 有問題需要 rollback,rollback 本身也需要被測試過。 Down migration 有沒有寫 大部分的 migration 工具(Django migrations、Flyway、Liquibase)支援 up migration 和 down migration。Down migration 是「回滾這次改動」的腳本。 問題:很多人只寫 up migration,down migration 留空或不寫。Rollback 的時候發現 down migration 沒有實作,就需要手動修資料。 測試方法:在 staging 跑 up migration,然後跑 down migration,確認 schema 回到原始狀態,資料也沒有損毀。 Rollback 後的資料完整性 如果 up migration 已經新增了一些用新 schema 格式的資料,down migration 回滾後,這些資料怎麼辦? 這個問題需要在 migration 設計階段就想清楚,QA 要確認 PM 和 RD 對這個情境有共識。 實際的測試流程 結尾 那個只影響老用戶的 ENUM bug,事後做了 post mortem,結論是:Migration 測試只測了「Migration 本身」,沒有測「Migration 後,舊的程式碼假設是否仍然成立」。 加了一條新的測試規則:每次 Schema 有改動,要 review 所有依賴這個欄位的程式碼,確認沒有隱性假設(hardcoded index、隱含的 ENUM 順序等)。 Migration 是後端工作,但它的影響是跨整個系統的。QA 在這裡的價值,是確認「改動後的行為和預期相符」——特別是針對那些最難測的、有歷史狀態的老用戶。 參考資料 Martin Fowler:Evolutionary Database Design — 資料庫漸進式設計的完整論述,Migration 測試策略的理論基礎 Flyway 官方文件 — 常用的資料庫版本管理工具 Django Migrations 官方文件 — Django ORM 的 Migration 系統說明 Liquibase 官方文件 — 跨資料庫平台的 Schema 版本控制工具 DORA 2024 研究報告 — 資料庫變更管理對軟體交付效能的影響