Giới thiệu về Phát triển Hướng Kiểm thử (TDD)

Table of Contents
TDD (Test-Driven Development)
TDD (Test-Driven Development)
Giai đoạn Đỏ
Giai đoạn Đỏ
Giai đoạn Xanh
Giai đoạn Xanh
Giai đoạn Tái cấu trúc
Giai đoạn Tái cấu trúc
Giới thiệu về Phát triển Hướng Kiểm thử (TDD)
Trong một thời gian dài, tôi đã viết các bài kiểm tra theo cách mà hầu hết các nhà phát triển vẫn làm: sau khi viết mã. Tôi sẽ hoàn thành một tính năng, cảm thấy khá hài lòng về nó, sau đó viết các bài kiểm tra để xác nhận nó hoạt động đúng như tôi nghĩ. Các bài kiểm tra luôn vượt qua. Đó là sai lầm đầu tiên của tôi.
Một buổi chiều nọ, tôi tái cấu trúc một hàm tiện ích — dọn dẹp nó, làm cho nó "tốt hơn" — và làm hỏng nó theo một cách mà tôi không nhận ra trong hai ngày. Các bài kiểm tra hiện có đang kiểm tra cách triển khai của tôi, chứ không phải hành vi. Khi tôi thay đổi cách triển khai, các bài kiểm tra cũng thay đổi theo. Không ai phát hiện ra cho đến khi QA.
Đó là lúc tôi thực sự thử TDD. Không phải vì ai đó bảo tôi làm, mà vì tôi đã quá mệt mỏi với kiểu lỗi cụ thể đó.
Chu trình TDD
| Giai đoạn | Hành động | Tư duy | Mục tiêu |
|---|---|---|---|
| 🔴 Đỏ | Viết bài kiểm tra thất bại | Định nghĩa hành vi mong muốn trước | Bài kiểm tra mô tả API |
| 🟢 Xanh | Viết mã tối thiểu để vượt qua | Chống lại việc thiết kế quá mức | Làm cho bài kiểm tra vượt qua — không hơn |
| 🔵 Tái cấu trúc | Cải thiện thiết kế & loại bỏ trùng lặp | Các bài kiểm tra là lưới an toàn của bạn | Mã sạch trong khi vẫn giữ màu xanh |
TDD tuân theo một nhịp điệu ba bước lặp lại. Một khi bạn đã thực hiện nó vài lần, nó sẽ trở thành phản xạ — nhưng vài lần đầu tiên nó có vẻ ngược đời.
🔴 Đỏ
🟢 Xanh
🔵 Tái cấu trúc
Một ví dụ cụ thể: Phép nhân
Ví dụ trong sách giáo khoa nhỏ, nhưng việc thực hiện nó từ từ là đáng giá.
Bước 1 — Đỏ (Kiểm tra thất bại)
Viết bài kiểm tra trước. Nó thất bại — multiply chưa tồn tại. Không sao cả. Đó là mục đích.
test('multiplies two numbers', () => {
expect(multiply(3, 4)).toBe(12);
});
Bước 2 — Xanh (Làm cho nó vượt qua)
Chỉ viết đủ mã để đáp ứng bài kiểm tra. Không hơn. Không tối ưu hóa sớm.
function multiply(a, b) {
return a * b;
}
Bước 3 — Tái cấu trúc
Mã đã sạch ở đây. Nhưng khi mọi thứ phát triển, đây là nơi bạn loại bỏ sự trùng lặp, cải thiện cách đặt tên và dọn dẹp các trừu tượng — trong khi các bài kiểm tra xác nhận không có gì bị hỏng.
Đây là cách tái cấu trúc hướng tới sự đúng đắn trông như thế nào khi bạn thêm an toàn kiểu:
11 function multiply(a, b) {2+ if (typeof a !== 'number' || typeof b !== 'number') {3+ throw new TypeError('Both arguments must be numbers');4+ }25 return a * b;36 }
Tại sao nó thực sự hiệu quả
Tôi đã hoài nghi về những lợi ích thiết kế cho đến khi tôi thử TDD trên một đoạn mã có yêu cầu không rõ ràng. Việc viết bài kiểm tra trước buộc tôi phải hỏi: thứ này thực sự nên làm gì? Tôi phải định nghĩa giao diện trước khi viết bất kỳ logic nào. Hóa ra đó là câu hỏi khó hơn — và quan trọng hơn.
Những lợi ích
- Ít lỗi hơn — Các vấn đề được phát hiện ngay lập tức, không phải vài ngày sau trong QA.
- Thiết kế tốt hơn — Bạn định nghĩa giao diện trước khi triển khai. Thứ tự đó rất quan trọng.
- Tái cấu trúc không sợ hãi — Một bộ kiểm tra vững chắc có nghĩa là bạn có thể thay đổi mã mà không cần phải nín thở.
- Tài liệu sống — Các bài kiểm tra mô tả chính xác cách mã hoạt động. Chúng không nói dối.
| Không có TDD | Với TDD | |
|---|---|---|
| Phát hiện lỗi | Tìm thấy trong sản xuất hoặc kiểm thử thủ công | Phát hiện ngay lập tức trong quá trình phát triển |
| Thiết kế | Triển khai thúc đẩy thiết kế API | API được thiết kế trước (kiểm thử trước) |
| Tái cấu trúc | Rủi ro — không có lưới an toàn | Tự tin — các bài kiểm tra xác minh hành vi |
| Tài liệu | Tài liệu riêng biệt bị lỗi thời | Các bài kiểm tra = tài liệu luôn cập nhật |
Những sai lầm tôi mắc phải lúc đầu
- Viết quá nhiều mã trước khi chạy bài kiểm tra.
- Bỏ qua hoàn toàn bước Tái cấu trúc (nó không phải là tùy chọn).
- Kiểm tra chi tiết triển khai thay vì hành vi bên ngoài — những bài kiểm tra đó bị hỏng trong mỗi lần tái cấu trúc.
- Viết bài kiểm tra sau mã và gọi đó là TDD. Đó chỉ là kiểm thử.
Bắt đầu từ đâu
Bắt đầu nhỏ. Chọn một hàm tiện ích — một bộ định dạng, một bộ xác thực, một cái gì đó khép kín. Viết bài kiểm tra trước, xem nó thất bại, sau đó làm cho nó vượt qua. Một chu trình. Xem cảm giác thế nào.
Những lợi ích thiết kế không xuất hiện trong một hàm ba dòng. Chúng xuất hiện khi bạn đang xây dựng một cái gì đó có độ phức tạp thực sự và các bài kiểm tra của bạn liên tục cho bạn biết API đang gây nhầm lẫn ở đâu hoặc logic có quá nhiều trách nhiệm ở đâu. Đó là TDD đang làm công việc của nó.
TDD Testing JavaScript Best PracticesBạn cũng có thể thích
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

Kiểm thử đơn vị trong JavaScript: Các mẫu thực tế giúp ngăn chặn lỗi sản phẩm
Hướng dẫn thực tế về cách viết các bài kiểm thử đơn vị JavaScript bền vững: mẫu AAA, test fixture, kiểm thử dựa trên thuộc tính với fast-check và mocking biên.
Read more
Làm chủ kiểm thử E2E với Playwright vào năm 2026
Làm chủ kiểm thử E2E với Playwright vào năm 2026: tự động chờ, cách ly ngữ cảnh trình duyệt, chặn mạng, lưu trữ xác thực và song song hóa CI.
Read more
TypeScript Generics: Các Mẫu Nâng Cao cho API An Toàn Kiểu
Nắm vững các mẫu generics TypeScript nâng cao: conditional types, mapped types, template literal types, branded types, discriminated unions và xây dựng các thư viện sản xuất an toàn kiểu.
Read more