Test quality bar for this repo. Read when writing, reviewing, or designing tests — covers naming, abstraction level, assertions, determinism, and the process fo
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-test-quality-c39abd77d5df ,按照其中的说明把「test-quality」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
What "best practice for new work" means in this repo. Each rule carries its recorded reasoning where one exists; a rule with no stated why is a convention — follow it anyway.
test_elicit_form_decline_returns_no_content, never test_elicit_form_decline.test_* functions; no Test classes (legacy files have them — don't copy).assert params.name == "add"), proving the request
that arrived is the request the test sent.snapshot(...) equality,
so an added or dropped field fails. Regenerate with --inline-snapshot=fix so intentional
changes arrive as a reviewable diff; never hand-edit snapshot literals._meta, cursors) → identity against the same
variable you sent. A snapshot of a pass-through value only "matches" because a human checked
two literals correspond — it proves nothing.pytest.raises + .code against the named constant; snapshot SDK-authored
messages; never match= on message text. Third-party text (pydantic, jsonschema) → stable
prefix only — never pin text that changes with a dependency upgrade — with a comment saying so.anyio.Event so the wait ends exactly when the condition holds (that
discipline is why 529 e2e tests run in ~10 s). Sole exception: tests of time-based
features, with a comment.anyio.fail_after(5). 5 is the standard — widening it
needs an articulable reason; "10 to be safe" is covering up a flake, not fixing one, and
unexplained widenings propagate (one agent used 10 and every later one copied it).elapsed < 0.9 on a ~0.01 s
operation — a 90× margin — was still rejected in review. fail_after bounding a hang is the
only timing primitive allowed.start_soon
calls prove nothing. Gate with events so all parties are mid-flight before any proceeds, emit
interleaved, then assert the demux.# pragma, # type: ignore, # noqa by default — restructure first; a suppression
usually means a test or a type is missing. The narrow sanctioned escape hatches (and the
audit to run before pushing) are in AGENTS.md. In tests, narrow types with assert isinstance; never Any/object when a real type exists.filterwarnings = error). Fix the cause; if the fix can't land in the same change, scope the
suppression to the one fixture that needs it and track the real fix explicitly.raise NotImplementedError, so they cannot
silently become load-bearing.from __future__ import annotations (py310+ repo).src/ as a side effect — the one mechanical exception is deleting a
pragma a new test now covers. If a test can't be written without a library change, raise it
as a finding or defer the test; don't quietly edit src/.uv run --frozen pytest <file> -q + pyright + ruff while
iterating; full suite, coverage, and ./scripts/test (when src/ was touched) at
integration.Test classes, raciness). These rules define
the bar for new work.