Không refactor và viết test cùng lúc. Trình tự: bọc test quanh hành vi hiện tại trước, refactor sau, không đổi hành vi trong lúc refactor.
1. Ghi lại hành vi hiện có (characterization test). Không phán xét đúng/sai, chỉ ghi lại module đang trả ra cái gì với các đầu vào thật. Lấy dữ liệu từ log hoặc DB production (đã ẩn danh). Nếu đầu ra kỳ quặc thì vẫn assert theo cái kỳ quặc đó — có thể đang có hệ thống khác phụ thuộc vào nó.
2. Tạo điểm chèn (seam) để test được. Module cũ hay gọi thẳng DB/HTTP/new Date() bên trong. Tách phụ thuộc ra tham số hoặc bọc thành interface — đây là thay đổi nhỏ và cơ học, làm trước và commit riêng.
3. Test ở tầng cao nếu bên trong quá rối. Một test gọi qua API/HTTP endpoint và so sánh response còn hơn không có gì; nó phủ được luồng để bạn dám sửa bên trong.
4. Refactor từng bước nhỏ, chạy test sau mỗi bước. Không trộn "dọn code" với "thêm tính năng" trong cùng một commit — khi đỏ sẽ không biết do đâu.
Với hành vi thực sự khó bọc test, dùng thêm lưới ngoài: chạy song song code cũ và code mới trên cùng đầu vào production rồi so sánh kết quả (shadow run) trước khi chuyển hẳn.