Test Migration
Test Migration
medium 25-30 minutes🎯 Learning Objectives
- How to update test code when source code is refactored (renamed, moved, removed)
- Why word-boundary-aware replacement prevents corrupting similar identifiers
- How to handle import path updates when modules are moved
- Why tests must follow code — broken tests are worse than no tests
📖 Concept: Test Migration with Refactoring
Test migration คือการอัพเดท test code ให้ตรงกับ source code ที่เปลี่ยนไป — เหมือนการอัพเดทคู่มือฝึกสอนหลังจากเปลี่ยน technique ใหม่ ถ้า source code เปลี่ยนชื่อ function แต่ test ยังเรียกชื่อเก่า = tests จะ fail ทันที
หลักการสำคัญ: TESTS FOLLOW CODE — เมื่อ refactoring, tests ต้อง update ให้ตรง. AI tools มักจะทำ global string replace ซึ่งอันตราย — ถ้า rename get เป็น fetch, global replace จะเปลี่ยน getter เป็น fetchter (substring corruption)
Think of it like updating a martial arts manual after your master renames a technique — every reference must be updated precisely, or students will get confused and practice the wrong move.
⚙️ How It Works
The Test Migration Workflow
- Parse changes — extract type (rename/move/remove), old name, new name/path
- Apply transformations — word-boundary-aware rename, path update, line removal
- Verify — ensure no substring corruption
The Three Operations
Rename — word-boundary-aware replacement:
// ❌ Naive: global string replace"getData" → "fetchData" // CORRECT"getter" → "fetchter" // WRONG! Substring corruption
// ✅ Correct: word-boundary regexconst regex = new RegExp(`\\b${escapeRegex('get')}\\b`, 'g');"getData".replace(regex, 'fetchData') // → "fetchData" ✅"getter".replace(regex, 'fetchData') // → "getter" ✅ (untouched)Move — update import paths:
// Beforeconst { helper } = require("./old-module.js");
// After moveconst { helper } = require("./new-module.js");Remove — delete test lines referencing removed code:
// Beforetest("removedFunc", () => { expect(removedFunc()).toBe(1); });test("keepFunc", () => { expect(keepFunc()).toBe(2); });
// After remove removedFunctest("keepFunc", () => { expect(keepFunc()).toBe(2); });The Critical Rule: Word Boundaries
// ❌ Naive: .replace('get', 'fetch')"const { get } = require('./problem.js');""test('getter works', () => { expect(getter()).toBe(1); });"// After naive replace:"const { fetch } = require('./problem.js');""test('fetchter works', () => { expect(fetchter()).toBe(1); });" // CORRUPTED!
// ✅ Correct: word-boundary regex// "get" matches only as whole word, not inside "getter"💡 Example: Walkthrough
const tests = `const { getData } = require("./problem.js");test("getData works", () => { expect(getData()).toBe(1); });`;
const changes = [{ type: 'rename', oldName: 'getData', newName: 'fetchData' }];
// Word-boundary regex: \bgetData\b → fetchData// "getData" matches (whole word) ✅// No substring issues
// Output:const updated = `const { fetchData } = require("./problem.js");test("fetchData works", () => { expect(fetchData()).toBe(1); });`;⚠️ Common Mistakes
Mistake 1: Global string replace without word boundaries
“String.replace(oldName, newName) ทุกที่” →
get→fetchจะทำให้getterกลายเป็นfetchter— ใช้ word-boundary regex
Mistake 2: Not escaping regex special characters
“new RegExp(oldName, ‘g’)” → ถ้า oldName มี special chars (
.,*,+) regex จะพัง — ต้อง escape ก่อน
Mistake 3: Not removing test lines for removed code
“Rename สำเร็จแต่ลืมลบ test ของ removed function” →
removeoperation ต้องลบ test lines ที่ reference removed function
Mistake 4: Empty input crashes
“ไม่ได้ handle tests ว่าง” → Empty tests → return empty string
📝 Knowledge Check
📝 Knowledge Check
Q1:Why should you use word-boundary-aware replacement instead of simple string replace?
Q2:When source code removes a function, what should happen to its tests?
Q3:What regex pattern ensures only whole-word matches for renaming?
🏋️ Quest: Test Migration
Now it’s time to practice! Sync tests with refactored code.
-
Download ไฟล์เริ่มต้นของ quest:
Terminal window npx bluebeltdojo download quest-102-test-migrationcd quest-102-test-migration -
เปิด
problem.jsใน editor ของคุณพร้อมความช่วยเหลือของ AI -
Implement solution ตาม instructions ใน
problem.js -
ตรวจสอบ solution ของคุณ:
Terminal window node test.js -
ส่งคำตอบ:
Terminal window npx bluebeltdojo submit
💡 Tip: ทดสอบ edge case — ตรวจสอบว่า rename “get” ไม่ทำให้ “getter” กลายเป็น “fetchter”
คำใบ้
migrateTests(oldTests, changes)รับ test code string และ array ของ changes- Rename ต้องใช้ word-boundary-aware replacement — อย่าใช้ simple string replace
- Move operation ต้อง update import paths
- Remove operation ต้องลบ test lines ที่ reference removed function
- ถ้าติดขัด ดู
_solution/solution.js