Vibe Code
Giáo trình/Phần 5 — Quy trình & vận hành

Test như kẻ phá hoại

Test để TÌM chỗ hỏng, không phải để chứng minh chạy được. Sáu mức ưu tiên P0–P5, bốn loại kết luận, và vì sao HTTP 200 chưa phải thành công.

Cấp 540 phút đọc

Đổi mục đích trước đã

Test không phải để chứng minh app chạy được. Test là để TÌM chỗ nó hỏng.

Nghe như chơi chữ, nhưng nó đổi hẳn cách bạn làm. Người muốn chứng minh app chạy sẽ bấm đúng đường mà mình đã nghĩ khi viết. Người muốn tìm chỗ hỏng sẽ bấm hai lần, rút mạng giữa chừng, nhập tên 200 ký tự, và đăng nhập bằng tài khoản quyền thấp nhất.

Ai cũng hiểu điều này về mặt lý thuyết. Cách duy nhất để thực hiện nó là có một danh sách viết sẵn — vì khi tự nghĩ tại chỗ, bạn luôn nghĩ ra đúng những đường mình đã lường trước.

Thứ tự rủi ro

Khi hết thời gian, test theo thứ tự này, bỏ từ dưới lên:

1. MẤT DỮ LIỆU      ← nặng nhất, không sửa được
2. BẢO MẬT          ← người khác xem/sửa được dữ liệu không thuộc họ
3. CHẶN LUỒNG CHÍNH ← không làm được việc chính
4. SAI SỐ LIỆU      ← chạy được nhưng kết quả sai
5. THẨM MỸ          ← xấu nhưng dùng được

Sáu mức P0 → P5

P0 — Smoke: app còn sống không? (2 phút)

  • Trang chính mở được, trả 200.
  • Đăng nhập được.
  • Màn hình chính hiện dữ liệu.
  • Console sạch lỗi.

P0 đỏ thì dừng lại, không test tiếp. Mọi kết quả sau đó đều vô nghĩa.

P1 — Luồng chính, trọn vẹn, đầu tới cuối (15 phút)

Không phải "gọi API thấy 200". Mà là: tạo dữ liệu → đóng app → mở lại → dữ liệu vẫn đúng → sửa → xóa → kiểm tác động sang nơi khác.

Ví dụ app đơn hàng:
[ ] Tạo đơn mới với dữ liệu thật có dấu tiếng Việt
[ ] Tải lại trang → đơn vẫn còn, đủ mọi trường
[ ] Số tổng ở trên có cộng thêm đơn này không?
[ ] Sửa đơn → kiểm cả bản ghi lịch sử (ai sửa, lúc nào)
[ ] Xóa đơn → báo cáo tháng có trừ đi không?
[ ] Đăng nhập bằng tài khoản KHÁC → có thấy đơn này đúng như quy định không?

Bắt buộc dùng tài khoản GHI ĐƯỢC. Tài khoản chỉ-xem không bao giờ lộ lỗi đường ghi — đây là bẫy đã làm lọt lỗi "không lưu được vào cơ sở dữ liệu" lên bản thật.

P2 — Đường xấu (20 phút) — nơi tìm được nhiều lỗi nhất

[ ] Bấm nút Lưu HAI LẦN thật nhanh → có ra hai bản ghi không?
[ ] Rút mạng giữa lúc đang gửi → có mất dữ liệu đang nhập không?
[ ] Để app mở 30 phút rồi thao tác → phiên hết hạn xử lý thế nào?
[ ] Nhập tên 500 ký tự → có vỡ giao diện / vỡ cơ sở dữ liệu không?
[ ] Nhập emoji và ký tự đặc biệt: 🙂 <script> ' " \ ; --
[ ] Bỏ trống mọi ô rồi bấm Lưu → báo lỗi có rõ không?
[ ] Nhập số âm vào ô tiền, nhập chữ vào ô số
[ ] Mở CÙNG bản ghi trên hai thiết bị, sửa cả hai, lưu cả hai
[ ] Bấm Quay lại giữa chừng rồi quay vào
[ ] Ngày 29/2, ngày 31 của tháng 30 ngày

Dòng "mở trên hai thiết bị, sửa cả hai" là dòng bắt được lỗi đắt nhất: một app POS từng bị mất món vì hai máy cùng sửa một đơn, máy lưu sau ghi đè máy lưu trước mà không ai được cảnh báo.

P3 — Vùng quanh chỗ vừa sửa (10 phút)

Lỗi hay nằm ở chỗ liên quan, không phải chỗ bạn vừa đụng.

[ ] Tính năng vừa sửa: chạy đúng
[ ] Tính năng DÙNG CHUNG mã với nó: còn chạy không?
[ ] Màn hình hiển thị cùng dữ liệu đó: còn đúng không?
[ ] Báo cáo/xuất file có dùng dữ liệu đó: số còn khớp không?

Mẹo: hỏi AI "liệt kê những gì có thể hỏng vì thay đổi này" và biến câu trả lời thành danh sách P3.

P4 — Đa môi trường (10 phút)

[ ] Mobile 375px — ngón tay thật, không phải chuột
[ ] Desktop 1280px và 1440px
[ ] Một máy ĐỜI CŨ nếu người dùng của bạn có (iPhone 7/8 còn nhiều)
[ ] Mạng 4G chậm, không phải Wi-Fi nhà
[ ] Cửa sổ ẩn danh (không có bộ nhớ đệm, không cookie cũ)

P5 — Thẩm mỹ (5 phút)

Chữ bẻ dòng, khoảng cách lệch, chính tả. Sai chính tả là hỏng, không phải "chưa đẹp".

Bốn loại kết luận — không có loại thứ năm

Kết luận Nghĩa
ĐẠT Đã test, có bằng chứng, không thấy vấn đề
ĐẠT KÈM RỦI RO ĐÃ BIẾT Chạy được, nhưng có điều kiện X chưa xử lý — ghi rõ X
HỎNG Có vấn đề, không giao được
TẮC Không test được (thiếu tài khoản, thiếu dữ liệu, môi trường không dựng được)

TẮC không bao giờ được tính là ĐẠT. Đây là chỗ tự lừa mình phổ biến nhất: không test được tính năng xuất Excel vì chưa có dữ liệu thật → ghi "ok" → tuần sau khách bấm và nó vỡ.

Ba luật về bằng chứng

1. HTTP 200 chưa phải là thành công nghiệp vụ. API trả 200 kèm {"ok":true} nhưng dữ liệu không vào cơ sở dữ liệu là chuyện có thật. Phải đọc lại để kiểm:

curl -X POST https://app.com/api/don-hang --data-binary "@don.json" -H "cookie: phien=..."
# rồi ĐỌC LẠI
npx wrangler d1 execute app-db --remote --command "SELECT * FROM don_hang ORDER BY id DESC LIMIT 1"

2. Nút bị ẩn chưa phải là phân quyền. Giao diện ẩn nút Xóa với nhân viên — phải gọi thẳng API bằng curl để kiểm máy chủ có chặn không. Chi tiết ở Đăng nhập.

3. Đạt phải có bằng chứng quan sát được. Không viết "đã test ok". Viết: "Tạo đơn DH-0042, tải lại trang thấy đủ 7 trường, tổng tháng tăng từ 4.250.000 lên 4.310.000 đúng bằng giá trị đơn."

Báo cáo test phải nói rõ phần CHƯA testchuyên gia insight & case thực tế

Một kết luận không nói phần chưa test là một kết luận không dùng được — vì người đọc sẽ hiểu là "đã test hết".

Khuôn tôi dùng, ba phần:

ĐÃ TEST:   P0, P1 trọn luồng tạo-sửa-xóa đơn, P2 (bấm đúp, mất mạng,
           phiên hết hạn), P4 ở 375px và 1280px.
CHƯA TEST: xuất Excel với trên 1.000 dòng (chưa có dữ liệu thật);
           máy iPhone 8 (không có máy).
RỦI RO:    nếu đơn có ngày để trống thì bị lọc mất khỏi báo cáo.
           Hiện cơ sở dữ liệu không có đơn nào như vậy.
KẾT LUẬN:  ĐẠT KÈM RỦI RO ĐÃ BIẾT.

Ba dòng này mất 2 phút viết và chúng làm được hai việc: bảo vệ bạn khi có sự cố ("tôi đã ghi rõ chưa test phần đó"), và cho người quyết định đủ thông tin để quyết. Khách có thể nói "cứ lên đi, bên anh không có đơn thiếu ngày" — đó là quyết định của họ, và họ phải được quyền biết để quyết.

Danh sách test tự động — rẻ hơn bạn nghĩ

Phần P0 và một phần P1 nên tự động hóa. Đây đúng là ô xanh — giao cho AI:

Viết script Node (không dùng thư viện ngoài) kiểm app tại <url>:

P0:
1. GET /                          → 200, HTML có chứa "Đăng nhập"
2. GET /api/bootstrap (không cookie) → 401, dưới 1 giây

P1 (dùng tài khoản test GHI ĐƯỢC trong biến môi trường):
3. POST /api/dang-nhap            → 200 + có set-cookie
4. POST /api/don-hang dữ liệu hợp lệ CÓ DẤU TIẾNG VIỆT → 200
5. GET /api/don-hang              → dòng vừa tạo có mặt, CHỮ CÓ DẤU
                                     ĐÚNG, không bị ? hay mất dấu
6. POST /api/don-hang thiếu trường bắt buộc → 400 (không phải 500)
7. POST lại y hệt lần 4 (cùng mã đơn) → 409 (chống trùng)

P2:
8. GET /api/don-hang?moi_trang=999999 → số dòng trả về <= 100

In bảng: tên phép | mong đợi | thực tế | ĐẠT/HỎNG.
Thoát mã khác 0 nếu có phép hỏng, để CI chặn được.
Dữ liệu tiếng Việt ghi ra file tạm rồi gửi, không nhét vào dòng lệnh.

Chạy script này trong GitHub Actions trước mỗi lần deploy. 8 phép thử chạy 10 giây, và chúng bắt được phần lớn lỗi ngớ ngẩn.

Bốn bẫy khi tự động hóa phép thử
  1. App hoãn vẽ lại. Nhiều app gom thay đổi rồi mới vẽ sau 1–2 giây. Đo ngay sau thao tác là đo trạng thái cũ. Đợi điều kiện xuất hiện, đừng đợi một khoảng cố định.
  2. Đo chữ bẻ dòng bằng chiều cao phần tử là sai — nút có chữ căn giữa luôn cao hơn chữ. Phải đếm số hình chữ nhật của nút văn bản (mã ở bài UX).
  3. textContent dài không có nghĩa là hiển thị dài — có thể đang bị cắt bằng CSS.
  4. Dấu tiếng Việt chết trên dòng lệnh Windows. Ghi ra file rồi curl --data-binary @file. Dấu hiệu nhận ra: trong cùng một câu, chữ một dấu rụng dấu còn chữ nhiều dấu thành ?.
Tôi ghét test cho tới khi tôi đổi cách nghĩngười dùng bình thường góp ý

Với tôi test là việc buồn tẻ làm sau khi đã xong phần vui. Thứ đổi ý tôi là một cách nhìn khác: test là lúc mình đóng vai người khó tính nhất trong công ty.

Tôi bắt đầu nghĩ như chị kế toán của chúng tôi — người luôn tìm ra chỗ sai trong mọi bảng biểu. Chị ấy sẽ nhập gì? Chị ấy sẽ bấm gì? Tự nhiên việc test thành ra khá vui, như trò chơi tìm lỗi.

Và một mẹo rất thực dụng: tôi viết danh sách test TRƯỚC khi nhờ AI làm tính năng. Lúc đó tôi còn đang nghĩ về việc cần làm, chưa bị cuốn vào mã đã viết ra sao. Danh sách viết trước luôn khó hơn, và tốt hơn, danh sách viết sau.

Chốt review bài nàychuyên gia review
  • Đủ: đổi mục đích test, thứ tự rủi ro, P0–P5 có danh sách cụ thể, bốn loại kết luận, ba luật bằng chứng, khuôn báo cáo, đề tự động hóa, bốn bẫy.
  • Đã trả giá thật: lỗi đường ghi lọt vì tài khoản chỉ-xem; mất món vì hai máy cùng sửa; đo sai vì app hoãn vẽ lại.
  • Rủi ro còn lại: danh sách này bắt lỗi kỹ thuật. Nó không bắt được "tính năng này làm ra không ai cần" — việc đó thuộc vòng phản hồi thật.
Bài tập chốt
  1. Viết danh sách test P0–P2 cho app của bạn, vào file TEST.md trong repo.
  2. Chạy nó bằng tay một lượt, ghi kết quả theo đúng khuôn ba phần (đã test / chưa test / rủi ro).
  3. Tự động hóa phần P0 + P1 theo đề ở trên, nối vào CI.
  4. Phép thử tự lừa mình: đếm xem trong lần test vừa rồi, bạn tìm ra bao nhiêu lỗi. Nếu là 0, nhiều khả năng bạn đang test để chứng minh app chạy. Quay lại P2 và làm cho đủ.