Câu trả lời trung thực và có sức thuyết phục hơn "có, luôn luôn": áp dụng theo tình huống, không theo giáo điều.
TDD phát huy tốt khi:
- Yêu cầu rõ ràng và có thể diễn đạt bằng đầu vào/đầu ra: tính giá, luật chiết khấu, parse dữ liệu, chuyển trạng thái.
- Sửa bug — viết test tái hiện trước là cách dùng TDD dễ nhất, hiệu quả nhất.
- Code khó chạy tay để thử (job chạy nền, xử lý webhook): viết test còn nhanh hơn dựng cả luồng để bấm thử.
- Refactor có lưới an toàn sẵn.
TDD kém hiệu quả khi:
- Đang dò đường, chưa biết thiết kế ra sao (prototype, tích hợp API bên thứ ba chưa rõ response). Lúc này viết test trước là đóng băng một thiết kế mình chưa hiểu. Cách dùng được: làm bản nháp cho chạy được, rồi vứt đi và viết lại kèm test.
- Code chủ yếu là layout giao diện, tinh chỉnh CSS.
- Code chỉ nối các thành phần lại với nhau — test loại này gần như chỉ mock rồi assert mock.
Điều TDD mang lại rõ nhất không phải là số test, mà là áp lực thiết kế: hàm khó viết test thường là hàm đang ôm quá nhiều phụ thuộc. Khi thấy phải mock 6 thứ mới chạy được, đó là tín hiệu tách module chứ không phải tín hiệu bỏ test.