TDD cho người mới: vòng lặp đỏ - xanh - refactor qua ví dụ

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

TDD (Test-Driven Development) nghe có vẻ ngược đời: viết test trước khi viết code. Nhưng khi thử qua một vòng nhỏ, bạn sẽ thấy nó giúp bạn nghĩ rõ yêu cầu và viết code đơn giản hơn. Bài này đi qua nhịp đỏ - xanh - refactor bằng một ví dụ cụ thể.

Ba bước của vòng lặp TDD

  1. Đỏ (Red): viết một test mô tả hành vi mong muốn. Chạy lên, test phải thất bại (vì chưa có code).
  2. Xanh (Green): viết lượng code ít nhất đủ để test qua. Không cần hoàn hảo.
  3. Refactor: dọn dẹp code (và cả test) khi test vẫn xanh. Đặt tên lại, loại bỏ lặp.

Sau đó lặp lại với hành vi tiếp theo. Mỗi vòng thường chỉ vài phút.

Ví dụ: hàm kiểm tra mật khẩu mạnh

Yêu cầu: hàm isStrongPassword(pw) trả về true nếu mật khẩu có ít nhất 8 ký tự, có chữ hoa và có chữ số. Ta làm từng bước nhỏ với Jest.

Vòng 1: độ dài tối thiểu

Đỏ, viết test trước:

const { isStrongPassword } = require('./password');test('mật khẩu ngắn hơn 8 ký tự là yếu', () => {expect(isStrongPassword('Ab1')).toBe(false);});

Chạy sẽ lỗi vì hàm chưa tồn tại. Xanh, viết code tối thiểu:

function isStrongPassword(pw) {return pw.length >= 8;}module.exports = { isStrongPassword };

Test qua. Chưa cần refactor.

Vòng 2: yêu cầu chữ hoa

Đỏ:

test('thiếu chữ hoa là yếu', () => {expect(isStrongPassword('abcdefg1')).toBe(false);});

Test này thất bại vì hàm hiện tại trả true. Xanh:

function isStrongPassword(pw) {return pw.length >= 8 && /[A-Z]/.test(pw);}

Vòng 3: yêu cầu chữ số, rồi refactor

test('thiếu chữ số là yếu', () => {expect(isStrongPassword('Abcdefgh')).toBe(false);});test('mật khẩu đủ điều kiện là mạnh', () => {expect(isStrongPassword('Abcdefg1')).toBe(true);});

Sau khi code qua, ta refactor cho dễ đọc, test vẫn xanh:

const MIN_LENGTH = 8;function isStrongPassword(pw) {const longEnough = pw.length >= MIN_LENGTH;const hasUpper = /[A-Z]/.test(pw);const hasDigit = /[0-9]/.test(pw);return longEnough && hasUpper && hasDigit;}

Vì sao TDD có ích?

  • Buộc làm rõ yêu cầu: không viết được test nghĩa là bạn chưa hiểu rõ cần gì.
  • Code dễ test: vì viết test trước, bạn tự nhiên thiết kế hàm nhỏ, ít phụ thuộc.
  • Phản hồi nhanh: lỗi bị phát hiện trong vài phút, không phải vài ngày.
  • Tự tin refactor: bộ test lớn dần là lưới an toàn.
  • Tránh viết thừa: chỉ viết code đủ cho test, không "phòng hờ".

Những hiểu lầm và khó khăn thường gặp

  1. "TDD làm chậm." Ban đầu có thể chậm hơn, nhưng thời gian debug và sửa lỗi sau này giảm. Hiệu quả tùy bối cảnh và kinh nghiệm của nhóm.
  2. "Phải TDD cho mọi thứ." Không bắt buộc. TDD hợp với logic nghiệp vụ, thuật toán, hàm xử lý dữ liệu; với giao diện hoặc thử nghiệm nhanh, nhiều người viết test sau.
  3. Bước quá lớn: viết test khổng lồ cùng lúc. Hãy quay về bước nhỏ nhất có thể.
  4. Bỏ qua bước refactor: code qua test rồi bỏ đó, dần dần thành mớ hỗn độn.
  5. Viết test không thất bại trước: nếu test xanh ngay từ đầu, nó có thể không kiểm tra điều bạn nghĩ.

Mẹo luyện TDD

  • Bắt đầu với các bài toán nhỏ, rõ yêu cầu như FizzBuzz, đổi số La Mã, kiểm tra năm nhuận.
  • Chọn trường hợp đơn giản nhất làm test đầu tiên, rồi tăng dần độ phức tạp.
  • Giữ vòng lặp ngắn: nếu quá 10 phút mà test vẫn đỏ, hãy chia nhỏ bước.
  • Chạy test liên tục bằng chế độ watch (jest --watch) để có phản hồi tức thì.

Kết luận

TDD không phải phép màu, mà là một kỷ luật: nghĩ trước, làm đủ dùng, dọn dẹp sau. Hãy thử với một hàm nhỏ trong tuần này và xem nó thay đổi cách bạn suy nghĩ về code ra sao.

Nếu bạn muốn thực hành kiểm thử và thiết kế code với bài tập cụ thể, có thể tham khảo các khóa học trên codebem.com.

author_photo
Nguyễn Đình Cường

0 comment