---
title: "Kiểm thử khi code do AI viết: tránh bài test luôn xanh"
url: https://www.thinnd.site/ky-thuat/kiem-thu-code-do-ai-viet/
language: vi
author: "Nhu Duy Thin (Thinnd)"
published: 2026-10-29
updated: 2026-10-29
section: "Kỹ thuật phần mềm"
tags: ["kiểm thử", "test", "AI", "kiểm thử đột biến", "property-based testing", "chất lượng"]
summary: "Khi AI viết cả code lẫn test, bài test dễ chỉ khớp với code vừa viết chứ không khớp với yêu cầu, nên luôn xanh mà không bắt được lỗi. Độ phủ cao cũng không đủ: một bài nghiên cứu về sinh test bằng mô hình ngôn ngữ nêu có bộ test đạt 100% độ phủ nhưng chỉ khoảng 4% điểm đột biến. Bảy cách giữ test có giá trị: viết test từ đặc tả chứ không từ code, thấy test đỏ trước khi sửa, tự làm hỏng code để xem test có đỏ không, dùng kiểm thử đột biến, kiểm thử theo thuộc tính, bảng giá trị biên và chạy thật một lần."
license: "Cite with the author name and the canonical URL above."
---

# Kiểm thử khi code do AI viết: tránh bài test luôn xanh

> Dành cho người viết hoặc duyệt code có AI tham gia, kể cả người mới. Từ kỹ thuật nào cũng có giải thích ngắn.
>
> Ví dụ mã và các con số trong ví dụ là **dựng lại** để dễ hình dung. Con số "100% độ phủ, 4% điểm đột biến" lấy từ phần tóm tắt của một bài báo (mình chưa đọc toàn văn). Các công cụ được nhắc tên chỉ để làm ví dụ, mình chưa chạy chúng. Các cách làm là **gợi ý của mình**.

---

## Tóm tắt nhanh

- Khi **AI viết cả code lẫn test**, test dễ chỉ xác nhận code, không xác nhận yêu cầu.
- **Test xanh chưa đủ.** Độ phủ cao cũng chưa đủ: có bộ test phủ 100% mà bắt được rất ít lỗi.
- Câu hỏi đúng không phải "test có xanh không" mà là **"nếu code sai, test có đỏ không?"**
- **Bảy cách**: viết từ đặc tả, thấy đỏ trước, tự làm hỏng code, kiểm thử đột biến, theo thuộc tính, bảng giá trị biên, chạy thật.
- Bắt đầu bằng thứ rẻ nhất: **làm hỏng code bằng tay** và xem test.

---

## Từ khó, nói dễ

| Thuật ngữ | Nói dễ hiểu |
|---|---|
| **Test (bài kiểm tra)** | Đoạn code chạy thử code khác và so kết quả với điều mong đợi. |
| **Độ phủ (coverage)** | Tỷ lệ dòng code được test chạy qua. Không nói test có kiểm tra đúng hay không. |
| **Kiểm thử đột biến** | Cố ý làm hỏng code một chút rồi xem test có đỏ không. |
| **Điểm đột biến** | Tỷ lệ các bản làm hỏng bị test bắt được. |
| **Kiểm thử theo thuộc tính** | Thay vì vài ví dụ, mô tả một quy luật luôn đúng và để công cụ thử rất nhiều đầu vào. |
| **Giá trị biên** | Giá trị nằm đúng ranh giới của quy tắc, như đúng 500 nghìn. |
| **Test luôn xanh** | Test không bao giờ thất bại dù code sai. |

---

## 1. Vấn đề: người viết test cũng là người viết code

Khi một người viết code rồi viết test, người đó thường **mang theo cùng một cách hiểu** vào cả hai. Nếu họ hiểu sai yêu cầu, code sai và test cũng sai theo, nên test xanh. Với AI, chuyện này còn dễ xảy ra hơn: AI viết test **sau khi đã có code** và nhìn thấy code, nên test thường được dựng để khớp với điều code đang làm.

Đó là lý do trong [danh sách 15 điểm duyệt code do AI viết](https://www.thinnd.site/ky-thuat/duyet-code-do-ai-viet/) có hai điểm riêng về test: test có kiểm tra điều quan trọng không, và test do chính AI viết thì phải thử làm hỏng code xem có đỏ không.

Và đây không chỉ là cảm giác. Bài báo về sinh test bằng mô hình ngôn ngữ theo hướng đột biến (MutGen, 2025) lập luận rằng **độ phủ là chỉ báo yếu về khả năng phát hiện lỗi**, và nêu có bộ test đạt **100% độ phủ nhưng chỉ khoảng 4% điểm đột biến**. Mình đọc phần tóm tắt nên hãy coi con số này là minh họa của vấn đề, không phải thống kê chung.

---

## 2. Ví dụ: ranh giới 500 nghìn

*Ví dụ dựng lại.* Yêu cầu: **đơn từ 500 nghìn trở lên được giảm 10%.**

AI viết:

```js
function giamGia(tong) {
  return tong > 500000 ? tong * 0.9 : tong;
}

test("đơn lớn được giảm 10%", () => {
  expect(giamGia(600000)).toBe(540000);
});

test("đơn nhỏ không được giảm", () => {
  expect(giamGia(100000)).toBe(100000);
});
```

Cả hai test đều xanh, độ phủ 100%. Nhưng code sai: yêu cầu là "từ 500 nghìn **trở lên**", mà code dùng `>`, nên đơn **đúng 500.000** không được giảm.

**Làm hỏng thử bằng tay.** Đổi `>` thành `>=`, tức là sửa code cho **đúng** yêu cầu. Chạy lại test: **vẫn xanh**. Vậy là hai bài test không phân biệt được code sai với code đúng ở ranh giới. Đây gọi là một "bản đột biến còn sống".

**Thêm một bài test từ đặc tả:**

```js
test("đúng 500.000 thì được giảm", () => {
  expect(giamGia(500000)).toBe(450000);
});
```

Bài này **đỏ** với code hiện tại, và xanh sau khi sửa. Đây là bài test có giá trị: nó **thất bại khi code sai**.

---

## 3. Bảy cách giữ test có giá trị

### Cách 1: viết test từ đặc tả, không từ code

Nhìn vào **yêu cầu**, không nhìn vào code, rồi viết ví dụ. Bài [Phát triển theo đặc tả](https://www.thinnd.site/ky-thuat/phat-trien-theo-dac-ta/) gợi ý viết trước ba đến sáu ví dụ chấp nhận được, kể cả ca lạ. Đó chính là các bài test cần có.

Nếu bắt buộc phải nhờ AI viết test, hãy cho nó **đặc tả và ví dụ**, đừng chỉ cho code.

### Cách 2: thấy test đỏ trước

Viết test **trước khi** sửa, chạy và **thấy nó đỏ vì đúng lý do**, rồi mới sửa cho xanh. Test mà bạn chưa từng thấy đỏ thì bạn chưa biết nó có bắt được gì không.

Tài liệu thực hành của Anthropic dùng đúng ý này khi gợi ý yêu cầu cho agent: "viết một test thất bại tái hiện lỗi, rồi sửa".

### Cách 3: tự làm hỏng code

Cách rẻ nhất, không cần công cụ. Sau khi test xanh, **cố ý sửa sai code một chút** rồi chạy lại:

- Đổi `>` thành `>=`, hoặc ngược lại.
- Đổi `0.9` thành `0.8`.
- Xóa một điều kiện, hoặc đổi `&&` thành `||`.
- Trả về một giá trị cố định.

Nếu test vẫn xanh, bạn vừa tìm ra một chỗ test không kiểm tra. Rồi hoàn tác thay đổi.

### Cách 4: kiểm thử đột biến tự động

Làm việc ở cách 3 một cách có hệ thống: công cụ tự tạo nhiều bản làm hỏng nhỏ và báo bản nào **còn sống** (test không bắt được). Có công cụ cho từng ngôn ngữ, ví dụ Stryker (JavaScript), mutmut (Python), PIT (Java). Mình nhắc để bạn tìm hiểu, không phải đã chạy trong bài này.

Lưu ý: kiểm thử đột biến **chậm** và có thể cho nhiều "bản sống" không đáng quan tâm. Hãy dùng cho phần lõi quan trọng, không cần cho cả dự án.

### Cách 5: kiểm thử theo thuộc tính

Thay vì vài ví dụ, bạn mô tả **một quy luật luôn đúng**, và công cụ thử rất nhiều đầu vào ngẫu nhiên. Ví dụ với hàm giảm giá:

- Kết quả **không bao giờ lớn hơn** tổng ban đầu.
- Với mọi tổng **từ 500.000 trở lên**, kết quả bằng đúng 90%.
- Với mọi tổng **dưới 500.000**, kết quả bằng tổng.

Công cụ như Hypothesis (Python) hay fast-check (JavaScript) làm việc này. Chúng hay tìm ra những giá trị biên mà bạn không nghĩ tới.

### Cách 6: bảng giá trị biên

Với mỗi quy tắc có ngưỡng, viết **ba giá trị**: ngay dưới, đúng bằng, ngay trên.

| Đầu vào | Mong đợi |
|---|---|
| 499.999 | 499.999 (không giảm) |
| 500.000 | 450.000 (giảm) |
| 500.001 | 450.000,9 (giảm) |

Cộng với các ca lạ: 0, số âm, rất lớn, sai kiểu, rỗng.

### Cách 7: chạy thật một lần

Test đơn vị không thay được việc **mở ra và dùng thử**. Bài [Ba tiếng làm việc với một AI agent](https://www.thinnd.site/ky-su/nhat-ky-ai-agent-du-an-that/) có những lỗi mà kiểm tra logic không bắt được vì chúng là điều mắt người thấy. Hãy chạy ứng dụng, bấm thử đường chính, và ghi lại.

---

## 4. Mùi của một bài test yếu

Khi duyệt test do AI viết, tìm những dấu hiệu này:

| Dấu hiệu | Vì sao yếu |
|---|---|
| **Không có kiểm tra** (không `expect` hay `assert`) | Chỉ chạy qua dòng code, không so kết quả |
| **Kiểm tra điều hiển nhiên** (kết quả không rỗng, đúng kiểu) | Gần như luôn đúng |
| **So kết quả với chính nó** | Luôn đúng, không phát hiện gì |
| **Giả lập (mock) mọi thứ** rồi kiểm tra rằng giả lập được gọi | Chỉ kiểm tra giả lập, không kiểm tra hành vi |
| **Chụp lại đầu ra hiện tại làm đáp án** | Mọi lỗi hiện có thành "đúng" |
| **Bắt và nuốt lỗi** rồi báo xanh | Che mất thất bại |
| **Chỉ thử một giá trị đẹp** (như 600.000) | Bỏ sót biên và ca lạ |
| **Mong đợi tính từ cùng công thức với code** | Sai cùng một kiểu thì xanh cùng nhau |

Mỗi bài test nên trả lời được: **"Nếu code sai kiểu gì thì bài này đỏ?"**

---

## 5. Danh sách kiểm sáu câu khi duyệt test do AI viết

1. Test được viết **từ đặc tả** hay từ code?
2. Mình đã **thấy nó đỏ** ít nhất một lần chưa?
3. Mình **làm hỏng code một chút** thì test có đỏ không? (Thử ít nhất một lần ở chỗ quan trọng.)
4. Đã có **bảng giá trị biên** cho mọi ngưỡng chưa?
5. Có **kiểm tra thật** (không chỉ chạy qua) và **không có mock thừa**?
6. Đã **chạy thật** đường chính của ứng dụng chưa?

---

## 6. Khi nhờ AI viết test, nên nhờ thế nào

*Gợi ý của mình.* Thay vì "viết test cho hàm này", hãy thử:

> "Đây là đặc tả và ba ví dụ chấp nhận được (ví dụ ở trên). Viết test từ đặc tả, **không từ code hiện có**. Gồm giá trị ngay dưới, đúng bằng và ngay trên mỗi ngưỡng. Sau đó **cố ý làm hỏng code theo ba cách** và cho mình biết test nào đỏ. Cho mình xem lệnh đã chạy và đầu ra."

Yêu cầu cuối cùng cũng là cách để agent **tự kiểm**, đúng như bài [Bảy sai lầm khi viết yêu cầu cho agent](https://www.thinnd.site/kinh-nghiem/bay-sai-lam-viet-yeu-cau-cho-agent/).

---

## 7. Nhìn cân bằng

- **Số liệu trong bài chỉ là một mảnh.** Mình chưa đọc toàn văn bài báo MutGen, và chưa có đo đạc riêng cho code do AI viết trong dự án này.
- **Kiểm thử đột biến tốn thời gian.** Dùng có chọn lọc, và đừng chạy theo điểm 100%.
- **Test không phải thứ duy nhất.** Duyệt code, theo dõi lỗi sau phát hành và chạy thật đều cần.
- **Test tốt cũng có chi phí bảo trì.** Quá nhiều test chi tiết có thể làm việc sửa code chậm đi.
- **Ví dụ 500 nghìn là dựng lại**, nhưng kiểu lỗi (sai ở biên) rất thật và phổ biến.

---

## 8. Kết luận

Test xanh chỉ nói rằng **test và code nhất trí với nhau**, không nói rằng cả hai đúng. Khi AI viết cả hai, sự nhất trí đó dễ đến từ cùng một nhầm lẫn. Câu hỏi đáng hỏi là **"nếu code sai, test có đỏ không?"**, và cách rẻ nhất để biết là làm hỏng code và xem.

Việc nhỏ làm ngay: chọn một hàm quan trọng có test do AI viết, đổi một dấu so sánh hoặc một con số trong hàm, và chạy lại test. Nếu vẫn xanh, bạn vừa tìm ra bài test đầu tiên cần viết.

---

## Nguồn tham khảo

- [On Mutation-Guided Unit Test Generation (MutGen), arXiv:2506.02954](https://arxiv.org/html/2506.02954v2)
- [Anthropic: Best practices for Claude Code](https://code.claude.com/docs/en/best-practices)
- Bài liên quan trong blog: [Duyệt code do AI viết](https://www.thinnd.site/ky-thuat/duyet-code-do-ai-viet/), [Phát triển theo đặc tả](https://www.thinnd.site/ky-thuat/phat-trien-theo-dac-ta/), [Bảy sai lầm khi viết yêu cầu cho agent](https://www.thinnd.site/kinh-nghiem/bay-sai-lam-viet-yeu-cau-cho-agent/), [Viết bài kiểm tra cho tính năng AI](https://www.thinnd.site/ky-thuat/viet-bai-kiem-tra-tinh-nang-ai/)
