AILapTrinh.comAI Lập Trình
Kiểm thử và rà soát mã AI viết

Viết unit test bằng AI: quy trình để bộ kiểm thử bắt được lỗi thật

Nhờ AI viết unit test mà không rơi vào bẫy kiểm thử chép lại mã: chuẩn bị đặc tả, câu lệnh mẫu, ví dụ pytest, cách đọc lại và gài lỗi thử độ nhạy.

Developer in Hanoi at a wooden desk with a laptop on a blank screen, hands writing expected values on a paper notepad, glass of iced coffee nearby, seen from behind

Nhờ AI viết unit test là một trong những việc đáng giao nhất, nhưng cũng là chỗ dễ tự lừa mình nhất: bộ kiểm thử chạy xanh hết không có nghĩa là mã đúng. Trợ lý AI đọc hàm của bạn rồi viết ra những ca kiểm thử khớp với chính cái hàm đó, kể cả chỗ sai. Muốn kiểm thử do AI viết bắt được lỗi thật, bạn phải cho nó một thứ để so ngoài bản thân đoạn mã: đặc tả, ví dụ đầu vào đầu ra, quy tắc nghiệp vụ.

Bài này đi qua một quy trình gọn cho lập trình viên dùng pytest, Jest hoặc PHPUnit: chuẩn bị gì trước khi hỏi, câu lệnh mẫu, cách đọc lại từng ca, mẹo cố tình làm hỏng mã để thử độ nhạy của bộ kiểm thử, và cách giữ bộ kiểm thử không mục theo thời gian. Mọi ví dụ trong bài là ví dụ giả định, mã ngắn để bạn chép về chạy thử.

Unit test do AI viết thường hỏng ở đâu

Lỗi phổ biến nhất có thể gọi là kiểm thử "chép lại mã". Bạn đưa hàm tính chiết khấu, AI đọc thấy hàm nhân giá với 0,9 khi khách là thành viên, thế là nó viết kiểm thử khẳng định giá 100 thành 90. Nếu quy tắc đúng của công ty là chỉ giảm 10% cho đơn từ một mức nhất định, cả hàm lẫn kiểm thử cùng sai một kiểu và cùng chạy xanh. Kiểm thử loại này không kiểm gì; nó chỉ chụp ảnh hành vi hiện tại của mã.

Lỗi thứ hai là khẳng định quá lỏng. Thay vì so kết quả cụ thể, AI hay viết những câu kiểm kiểu "kết quả không rỗng", "kết quả là một danh sách", "hàm không ném lỗi". Những câu đó gần như luôn qua, kể cả khi hàm trả về rác. Lỗi thứ ba là giả lập (mock) quá đà: mọi thứ hàm gọi tới đều bị thay bằng đồ giả trả sẵn giá trị, rốt cuộc kiểm thử chỉ xác nhận rằng hàm có gọi đúng những đồ giả đó theo đúng thứ tự.

Còn một lỗi khó chịu hơn: AI bịa ra tên hàm trợ giúp, tên fixture hoặc tham số của khung kiểm thử không có thật, hoặc dùng cú pháp của phiên bản cũ. Loại này lại dễ phát hiện vì chạy là báo lỗi ngay, miễn là bạn thật sự chạy. Đừng bao giờ tin câu "các kiểm thử đã qua" khi AI không có quyền chạy lệnh trên máy bạn; lúc đó nó chỉ đoán.

Chuẩn bị gì trước khi nhờ AI viết kiểm thử

Năm phút chuẩn bị quyết định chất lượng bộ kiểm thử nhiều hơn mọi mẹo câu lệnh. Trước khi mở khung trò chuyện, bạn gom đủ những thứ sau:

  • Đặc tả bằng lời của hàm. Hai đến năm câu nói hàm phải làm gì, viết theo quy tắc nghiệp vụ chứ không theo cách mã đang làm. Ví dụ: phí giao hàng miễn cho đơn từ mức X trở lên, đơn dưới mức đó tính theo cân nặng, phần lẻ làm tròn lên.
  • Ba đến năm cặp ví dụ vào ra do chính bạn tính tay. Đây là phần AI không tự sinh được một cách đáng tin, và cũng là phần biến kiểm thử từ "chụp ảnh mã" thành "đối chiếu với sự thật".
  • Tên khung kiểm thử và phiên bản ngôn ngữ. Ghi rõ pytest hay unittest, Jest hay Vitest, PHPUnit bản nào, Python hay Node bản nào, để AI không trộn cú pháp giữa các khung.
  • Một tệp kiểm thử có sẵn trong dự án làm mẫu. AI sẽ bắt chước cách đặt tên, cách dựng dữ liệu, cách tổ chức thư mục của nhóm bạn thay vì tự chế ra một kiểu mới.
  • Danh sách những gì được phép giả lập. Thường là mạng, đồng hồ hệ thống, cơ sở dữ liệu thật; còn logic tính toán của chính hàm thì không giả.

Nếu hàm đụng tới dữ liệu khách hàng, thay tên, số điện thoại, địa chỉ trong ví dụ bằng giá trị bịa trước khi dán vào chatbot. Mã nguồn của công ty cũng là tài sản: dán vào công cụ nào thì phải là công cụ công ty cho phép, đăng nhập bằng tài khoản công ty quản lý, không dùng tài khoản cá nhân cho tiện.

Câu lệnh mẫu và một ví dụ pytest

Câu lệnh tốt cho việc viết kiểm thử có bốn phần: bối cảnh, đặc tả, ví dụ do bạn tính, và yêu cầu về cách làm. Một mẫu bạn có thể chép rồi sửa (mức phí là ví dụ giả định):

"Viết kiểm thử pytest cho hàm tinh_phi_giao trong tệp dưới đây, Python 3.11. Quy tắc: đơn từ 500.000 đồng trở lên miễn phí; đơn nhỏ hơn tính 15.000 đồng cho 2 kg đầu, mỗi kg tiếp theo 5.000 đồng, phần lẻ kg làm tròn lên. Đây là bốn ví dụ đã tính tay: [...]. Viết mỗi quy tắc ít nhất một ca, thêm ca ở đúng mốc 500.000 đồng và đúng 2 kg. Không giả lập gì. Trước khi viết mã, liệt kê các ca định kiểm kèm lý do và chờ xác nhận."

Câu cuối là phần đáng giá nhất. Bắt AI liệt kê ca trước khi viết giúp bạn soát logic bằng mắt trong ba mươi giây và sửa ngay những ca nó hiểu sai quy tắc. Sau khi bạn xác nhận, kết quả nên trông gần như sau:

import pytest
from giao_hang import tinh_phi_giao

@pytest.mark.parametrize("tong_don, can_kg, mong_doi", [
    (500_000, 3.0, 0),        # đúng mốc: miễn phí
    (499_000, 2.0, 15_000),   # đúng 2 kg
    (499_000, 2.1, 20_000),   # lẻ 0,1 kg làm tròn lên 1 kg
    (200_000, 4.5, 30_000),   # 2 kg đầu + 3 kg
])
def test_phi_giao_theo_quy_tac(tong_don, can_kg, mong_doi):
    assert tinh_phi_giao(tong_don, can_kg) == mong_doi

Mỗi dòng trong bảng tham số là một ví dụ tính tay, đọc lên là hiểu quy tắc. Viết theo bảng như vậy cũng giúp người rà mã sau này thêm ca mới mà không phải chép lại cả hàm kiểm thử.

Đọc lại từng ca: năm câu hỏi phải trả lời

Giá trị mong đợi từ đâu ra? Với mỗi câu assert, tự hỏi con số bên phải dấu bằng đến từ đặc tả hay từ việc đọc mã. Nếu bạn không tự tính lại được trên giấy, đó là dấu hiệu AI đã lấy kết quả từ chính hàm đang kiểm.

Ca này hỏng thì có ai biết không? Một ca đáng giữ là ca sẽ đỏ khi có người sửa sai quy tắc. Ca kiểm "kết quả là số nguyên" không đỏ khi ai đó đổi mức miễn phí, nên với quy tắc đó nó gần như vô dụng.

Có ca nào kiểm cùng một điều hai lần không? AI thích viết nhiều; mười ca cùng kiểm đơn dưới mốc với các cân nặng nằm giữa khoảng chỉ làm bộ kiểm thử chậm và khó đọc. Gộp lại, giữ ca đại diện và ca ở mép.

Đồ giả có đang che logic thật không? Nếu hàm tính phí gọi một hàm khác để lấy bảng giá, giả lập bảng giá là hợp lý; giả lập luôn hàm làm tròn thì bạn đang kiểm thử đồ giả. Quy tắc nhớ nhanh: giả cái nằm ngoài ranh giới của đơn vị đang kiểm, không giả cái nằm bên trong.

Tên ca có nói được ý định không? Tên như test_case_1 không giúp ai hiểu vì sao kiểm thử đỏ. Đặt tên theo quy tắc: miễn phí khi đủ mốc, làm tròn phần lẻ lên. Khi chạy hỏng, tên đó là dòng thông báo đầu tiên người khác đọc.

Cố tình làm hỏng mã để thử độ nhạy của kiểm thử

Cách nhanh nhất để biết bộ kiểm thử có răng hay không là tự tay gài lỗi vào hàm rồi chạy lại. Không cần công cụ gì, mất chừng mười phút cho một hàm vừa phải.

  1. Chạy bộ kiểm thử lần đầu và xác nhận tất cả đều xanh trên máy của bạn, không phải theo lời báo của AI.
  2. Đổi một toán tử so sánh ở mốc quan trọng, ví dụ đổi lớn hơn hoặc bằng thành lớn hơn. Chạy lại. Phải có ít nhất một ca đỏ; nếu không, bạn đang thiếu ca ở đúng mốc.
  3. Bỏ bước làm tròn hoặc đổi làm tròn lên thành làm tròn xuống. Chạy lại và đếm số ca đỏ.
  4. Đổi một hằng số nghiệp vụ, như mức phí cho mỗi kg tiếp theo. Bộ kiểm thử tốt phải phản ứng với thay đổi này.
  5. Với mỗi lỗi gài mà không ca nào bắt được, tự viết thêm một ca hoặc nhờ AI viết một ca nhắm đúng chỗ đó, rồi trả mã về như cũ.
  6. Ghi các lỗi đã gài vào phần mô tả commit để người rà biết bộ kiểm thử đã được thử độ nhạy.

Đây là phiên bản làm tay của kiểm thử đột biến. Khi dự án lớn hơn, có công cụ tự sinh hàng loạt lỗi gài và báo tỉ lệ bị bắt; bài về độ phủ kiểm thử trong cùng chuyên mục nói kỹ phần đó. Với một hàm vừa viết, làm tay vẫn nhanh và dạy bạn nhiều hơn.

pytest, Jest, PHPUnit: dặn AI những gì cho từng khung

Mỗi khung kiểm thử có quy ước riêng, và AI hay trộn lẫn khi bạn không nói rõ. Bảng dưới là những điều nên ghi ngay trong câu lệnh; cú pháp chi tiết vẫn cần đối chiếu tài liệu chính thức của phiên bản bạn đang dùng.

KhungNên dặn AILỗi AI hay mắc
pytest (Python)Dùng assert trần, parametrize cho bảng ví dụ, fixture dùng chung đặt trong conftest.pyViết lẫn kiểu lớp của unittest, gọi fixture không tồn tại, quên cấu hình cho kiểm thử bất đồng bộ
Jest (JavaScript, TypeScript)Dùng describe và test, test.each cho bảng ví dụ, nói rõ dự án dùng CommonJS hay ES moduleQuên await với hàm trả về Promise nên kiểm thử kết thúc sớm, trộn cú pháp của khung khác
PHPUnit (PHP)Nói rõ bản PHPUnit và bản PHP, lớp kiểm thử kế thừa TestCase, dùng nhà cung cấp dữ liệu cho bảng ví dụDùng kiểu chú thích cũ hoặc thuộc tính mới không khớp phiên bản, đặt tên phương thức không bắt đầu bằng test

Lỗi quên await bên Jest đáng nói thêm: kiểm thử kết thúc trước khi Promise trả kết quả nên câu kiểm bên trong không bao giờ được chạy, và bạn thấy màu xanh giả. Khi đọc kiểm thử bất đồng bộ do AI viết, tìm từng chỗ gọi hàm async và xem có await hoặc return đứng trước không. Với PHPUnit, nếu dự án còn chạy bản cũ, nói rõ ngay câu đầu, vì AI thường mặc định cú pháp của bản mới nhất mà nó biết.

Giữ bộ kiểm thử không mục theo thời gian

Viết kiểm thử nhanh nhờ AI dễ dẫn tới phình to: vài tháng sau bộ kiểm thử chạy mất mười phút, mỗi lần đổi một dòng mã phải sửa hai chục ca. Lúc đó nhóm bắt đầu bỏ qua kiểm thử đỏ, và toàn bộ công sức thành vô ích.

Ba thói quen giúp tránh chuyện này. Thứ nhất, kiểm hành vi nhìn thấy từ bên ngoài, không kiểm chi tiết bên trong như hàm phụ riêng tư hay thứ tự gọi. Thứ hai, mỗi lần nhận một lô kiểm thử từ AI, xoá bớt những ca trùng trước khi commit; ít mà sắc tốt hơn nhiều mà nhạt. Thứ ba, khi một kiểm thử đỏ sau khi đổi quy tắc nghiệp vụ, sửa kiểm thử theo đặc tả mới, đừng nhờ AI "sửa kiểm thử cho khớp mã". Câu đó là cách nhanh nhất để xoá sạch giá trị của bộ kiểm thử.

Sau cùng, coi kiểm thử là tài liệu sống. Người mới vào nhóm đọc bảng tham số của hàm tính phí là hiểu quy tắc nhanh hơn đọc mã. Khi AI viết kiểm thử dễ đọc, bạn được cả hai thứ: lưới an toàn và bản mô tả nghiệp vụ không bao giờ lạc hậu, vì hễ nó lạc hậu là nó đỏ.

Câu hỏi thường gặp

AI có tự chạy được kiểm thử nó viết không?

Tuỳ loại công cụ. Chatbot thông thường không chạy được mã trên máy bạn nên mọi câu báo đã qua chỉ là phỏng đoán. Tác tử trong trình soạn thảo hoặc dòng lệnh có thể chạy lệnh nếu bạn cấp quyền, nhưng bạn vẫn nên tự chạy lại và đọc kết quả trước khi commit.

Nên để AI viết kiểm thử cho mã cũ chưa có kiểm thử nào không?

Được, nhưng hiểu rằng khi đó kiểm thử chỉ ghi lại hành vi hiện tại, đúng hay sai đều giữ nguyên. Đó vẫn là lưới an toàn hữu ích trước khi sửa mã, miễn là bạn ghi chú rõ những ca đang khẳng định hành vi mà bạn nghi là sai.

Độ phủ cao có nghĩa là kiểm thử AI viết tốt không?

Không. Độ phủ chỉ cho biết dòng mã nào đã được chạy qua, không cho biết kết quả có được kiểm hay không. Một bộ kiểm thử gọi mọi hàm mà không assert gì vẫn đạt độ phủ rất cao. Thử gài lỗi như trong bài để đo độ nhạy thật.

Có nên cho AI xem cả tệp mã nguồn khi viết kiểm thử không?

Nên cho xem chữ ký hàm và các kiểu dữ liệu liên quan, nhưng đặc tả và ví dụ vào ra phải đến từ bạn. Nếu chỉ đưa mã mà không có đặc tả, AI rất dễ viết kiểm thử chép lại hành vi của mã, kể cả lỗi đang nằm trong đó.

Kiểm thử AI viết có cần người rà như mã bình thường không?

Có, và rà kỹ không kém. Kiểm thử sai nguy hiểm theo kiểu riêng vì nó cho cảm giác an toàn giả. Khi rà, đọc giá trị mong đợi trước, tên ca sau, và với mỗi ca luôn hỏi nó sẽ đỏ trong tình huống nào.

Dùng dữ liệu thật của khách để kiểm thử cho sát thực tế được không?

Không nên. Dữ liệu trong kiểm thử nằm trong kho mã, ai có quyền đọc kho là đọc được. Dùng dữ liệu bịa có cùng hình dạng với dữ liệu thật, và che hết thông tin cá nhân trước khi dán bất cứ ví dụ nào cho AI.

Cần tư vấn cụ thể cho trường hợp của bạn?

Chúng tôi sẽ liên hệ trong vòng 24 giờ.

Đăng ký tư vấn ngay

Bài viết liên quan

Bạn cần hỗ trợ thêm?

Để lại thông tin, chúng tôi sẽ liên hệ trong 24 giờ.

hoặc
Gọi ngay 0926 138 138