•9 min read

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

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

TDD (Test-Driven Development)

Click to reveal
Testing
Một phương pháp phát triển phần mềm mà bạn viết các bài kiểm tra trước khi viết mã triển khai. Chu trình: Đỏ (kiểm tra thất bại) → Xanh (làm cho nó vượt qua) → Tái cấu trúc (dọn dẹp trong khi vẫn giữ các bài kiểm tra xanh).

TDD (Test-Driven Development)

TDD Cycle

Giai đoạn Đỏ

Click to reveal
TDD Cycle
Viết một bài kiểm tra thất bại vì mã triển khai chưa tồn tại. Điều này định nghĩa hành vi và API mong muốn.

Giai đoạn Đỏ

TDD Cycle

Giai đoạn Xanh

Click to reveal
TDD Cycle
Viết lượng mã tối thiểu cần thiết để làm cho bài kiểm tra vượt qua. Không hơn, không kém — hãy kiềm chế mong muốn thêm các tính năng bổ sung.

Giai đoạn Xanh

TDD Cycle

Giai đoạn Tái cấu trúc

Click to reveal
TDD Cycle
Dọn dẹp mã, loại bỏ sự trùng lặp, tối ưu hóa và cải thiện thiết kế trong khi vẫn giữ tất cả các bài kiểm tra vượt qua. Bộ kiểm tra là lưới an toàn của bạn.

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ể đó.


Audio Briefing
0:00 / 0:00

Chu trình TDD

Giai đoạnHành độngTư duyMụ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.

🔴 Đỏ

Viết một bài kiểm tra thất bại vì mã triển khai chưa tồn tại.

🟢 Xanh

Viết lượng mã tối thiểu cần thiết để làm cho bài kiểm tra vượt qua.

🔵 Tái cấu trúc

Dọn dẹp mã, loại bỏ sự trùng lặp và tối ưu hóa — trong khi vẫn giữ các bài kiểm tra vượt qua.

Advertisement

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:

javascript
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ó TDDVớ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 Practices
Advertisement

Bạn cũng có thể thích

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement