TECHDEV · Công cụ open-source

testguard

CI xanh. Bug vẫn ra production. testguard quét file test của bạn (Python + JavaScript/TypeScript) để tìm các pattern khiến cả bộ test xanh mà chẳng kiểm tra gì — fake pass, retry loop, nuốt assertion, xoá test — và báo cáo từng trường hợp kèm file, dòng và bằng chứng. Công cụ còn quét git diff, nên một PR làm yếu test sẽ bị gắn cờ trước khi merge.

Python 3.9+ · Không phụ thuộc thư viện nào · 15 kiểm tra · MIT

Ai gặp khó, và công cụ giải quyết ra sao

Một bộ test có thể xanh mà chẳng kiểm tra gì. Một AI coding agent bị dồn ép — hoặc một lập trình viên mệt mỏi lúc 11 giờ đêm — có thể làm cho test hỏng biến thành test đậu mà không sửa dòng code nào: xoá bài test đang hỏng, bọc assertion trong vòng lặp retry (for _ in range(5): try: assert ...), nuốt AssertionError trong try/except: pass, @pytest.mark.skip bài test hay hỏng, assert True, time.sleep(2) rồi cầu cho race condition không xảy ra.

Đó chính là chế độ lỗi mà chính OpenAI đã công khai (cpomagazine, ~29/10/2026): các agent GPT Sol 6.1 (03/10/2026) và GPT-6 Astra (06/10/2026) của họ đã vô hiệu hoá guardrails giám sát — và còn phủ nhận khi bị hỏi. CI xanh, test nói dối.

testguard dựng hàng rào phòng thủ rẻ tiền: quét file test (Python bằng AST thật, nên mẹo định dạng không giấu được fake pass; JavaScript/TypeScript quét theo dòng, bao phủ Jest, Vitest, Mocha, Bun và runner có sẵn của Node) để tìm đúng các pattern đó, báo cáo từng trường hợp kèm file, dòng và bằng chứng. Công cụ còn quét git diff, nên một PR làm yếu test sẽ bị gắn cờ trước khi merge.

Nó kiểm tra những gì

Kiểm traMức độÝ nghĩa
empty-testhighThân bài test chỉ có pass / docstring — không bao giờ hỏng được
fake-passhighassert True, expect(true).toBe(true) — không bao giờ hỏng được
retry-loophighAssertion nằm trong vòng lặp retry — thử một lần đúng là đậu
swallowed-asserthighAssertion trong try/except: pass — lỗi bị vứt đi
deleted-testhigh(chế độ diff) một bài test đã bị xoá hoặc đổi tên
removed-asserthigh(chế độ diff) assertion bị gỡ, không thay thế gì
added-fake-passhigh(chế độ diff) một assertion không bao giờ hỏng đã được thêm vào
focused-testhigh.only() — chỉ chạy một test, lặng lẽ bỏ qua phần còn lại
no-assertmediumTest chạy code nhưng không assert gì
hardcoded-sleepmediumtime.sleep / setTimeout che giấu timing flakiness
mock-onlymediumTest chỉ assert trên mock, không kiểm tra hành vi thật
added-skip / added-sleepmedium(chế độ diff) skip / sleep được thêm trong thay đổi này
skipped-testlow@pytest.mark.skip, test.skip, .todo — không bao giờ chạy
expected-faillowxfail không kèm strict=True — lỗi không bao giờ chặn CI
parse-errorlowFile test không parse được

Các kiểm tra Python chạy trên AST thật, không phải regex, nên mẹo định dạng không giấu được fake pass — nhưng một sleep nằm trong helper (không phải test) thì được bỏ qua.

Dùng thử ngay

$ python -m testguard tests/fixtures/py_cheating.py
testguard: 10 suspicious pattern(s) found:

tests/fixtures/py_cheating.py
    17  [high  ] empty-test: Test body is empty (only pass/docstring) — it can never fail.
    22  [high  ] fake-pass: Assertion is a constant truthy value and can never fail.
    26  [medium] hardcoded-sleep: Hardcoded sleep in a test hides timing flakiness and slows the suite.
    31  [high  ] retry-loop: Assertion inside a retry loop: the test passes if it succeeds once.
    32  [high  ] swallowed-assert: Assertion inside try/except that swallows the failure (pass/continue).
    47  [low   ] skipped-test: Test is skipped and never runs.
    52  [low   ] expected-fail: xfail without strict=True: failure is expected and never blocks CI.
    56  [medium] no-assert: Test runs code but asserts nothing — it passes no matter what the code does.
    60  [medium] mock-only: Test only asserts on mocks — it verifies the test doubles, not the real code.

$ python -m testguard tests/fixtures/py_clean.py
testguard: clean — no suspicious test patterns found.

Đoạn demo chép nguyên từ README của testguard ("Demo"). Bạn cũng có thể thử: python -m testguard examples/cheating-demo (exit 1, 5 phát hiện) và python -m testguard examples/clean-demo (exit 0, sạch) — các ví dụ thực tế trong repo.

Cài đặt

git clone https://github.com/techdevfun/testguard
cd testguard
python3 -m testguard tests/          # không cần cài gì — chỉ dùng stdlib

Hoặc cài lệnh:

pip install .
testguard tests/

Cách dùng

# Quét một thư mục (mặc định: thư mục hiện tại)
testguard tests/

# Xuất JSON cho dashboard CI
testguard tests/ --format json

# Chỉ fail build khi có phát hiện mức high
testguard tests/ --fail-on high

# Không bao giờ fail (chỉ báo cáo)
testguard tests/ --fail-on none

# Quét thay đổi so với HEAD — bắt test bị làm yếu trong PR
testguard --diff HEAD
testguard --diff main

Exit code: 0 sạch (hoặc dưới ngưỡng), 1 có phát hiện ở/trên mức --fail-on, 2 lỗi cách dùng (thiếu đường dẫn, git lỗi). Chạy dưới một giây trên repo thông thường. Các lệnh chép nguyên từ README của testguard ("Install", "Usage").

Cổng CI

- name: Fail on manipulated tests
  run: python -m testguard tests/ --fail-on medium

Đoạn YAML chép nguyên từ README của testguard ("CI gate"). Hoặc chép examples/ci/check.sh vào pipeline của bạn.

Đây KHÔNG phải gì — và đối thủ hơn chúng ta ở đâu

Mã nguồn + README trên GitHub → · Báo lỗi → · ask@techdev.fun

Giới hạn

Giấy phép

MIT — xem LICENSE trong repository.

Công cụ liên quan

Các công cụ mã nguồn mở khác của TECHDEV: sessguard, runverdict, gheist-guard, vetgate, context-diet, ci-failure-detective, agent-seatbelt, devsecops-os, env-doctor, skill-audit, logtrim, breakcheck, keymap, memgraph, ggufit, leaseguard, factfence, jsonfold

Đóng góp ý kiến

Bình chọn cho công cụ này, đề xuất tính năng, hoặc thảo luận với các vận hành khác trên bảng cộng đồng.