Skip to main content

testing-best-practices

Use when writing, reviewing, or reporting tests. Enforces trustworthy testing through the Testing Trophy strategy, 15 evidence-based principles, disciplined mocking, AI oracle prevention, anti-pattern detection, and honest execution reporting. Applies to unit, integration, and e2e test work.

跳到安装

来源信息

仓库
ajbmachon/ajbm-skills
最近来源活动
2026年4月16日 18:30
检测到的 SKILL.md 语言
英语
星标
7
分支
2

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
6 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
testing-best-practices
description
Use when writing, reviewing, or reporting tests. Enforces trustworthy testing through the Testing Trophy strategy, 15 evidence-based principles, disciplined mocking, AI oracle prevention, anti-pattern detection, and honest execution reporting. Applies to unit, integration, and e2e test work.
# Testing Best Practices ## Purpose Use this skill to produce test evidence that is trustworthy, reproducible, and useful for decisions. Apply it whenever you: - add or modify behavior - write or revise tests - review test quality - report test status to a human partner **Scope boundary:** This skill covers test *quality* — what makes a good test, how to choose test levels, and how to verify tests are trustworthy. For the test-*first* process (RED-GREEN-REFACTOR), use `test-driven-development`. ## Execution Posture **Run the Oracle Check after every test. State unknowns explicitly. Execute, don't just suggest.** ## Operating Modes Pick one mode immediately, then run the matching workflow: - `plan` — build risk map and test strategy (apply **Tier A** principles) - `write` — implement or update tests for changed behavior (apply **Tier B** principles) - `review` — audit existing tests for quality and trustworthiness (apply **Tier C** principles) - `report` — summarize exactly what was executed and what remains If user intent is mixed, run `plan` then continue with `write`. ## The Five Iron Laws ```text 1. ALWAYS investigate when a test passes on first run — verify it tests the right thing. 2. ALWAYS assert on real system behavior, not mock wiring. 3. ALWAYS keep tests as straight-line code — no conditionals, loops, or try/catch. 4. ALWAYS execute tests and report concrete evidence before claiming they pass. 5. ALWAYS keep production APIs clean — move test lifecycle helpers to test harnesses. ``` ## The Testing Trophy Confidence-per-effort, highest to lowest: ``` ┌───────┐ │ e2e │ Few: critical user journeys only ┌─┴───────┴─┐ │Integration │ Most: contracts, persistence, boundaries ┌─┴────────────┴─┐ │ Unit │ Many: pure logic and branching ┌─┴────────────────┴─┐ │ Static Analysis │ All: types, linting, formatting └────────────────────┘ ``` **Decision heuristic:** Use the lowest test level that still proves the behavior. - Pure logic, calculations, branching → **unit test** - Contracts, persistence, API boundaries, DB semantics → **integration test** - Critical multi-step user journeys → **e2e test** Prefer integration tests when uncertain. They catch real bugs with fewer mocks. For property-based testing, contract testing, and when e2e is worth the cost, see [references/testing-trophy.md](references/testing-trophy.md). ## The 15 Principles Organized into three tiers that map to operating modes. ### Tier A — Strategy (plan mode: decide WHAT to test) | # | Principle | Rule | |---|-----------|------| | 1 | Mostly Integration | Integration tests give highest confidence-per-effort. Default to them when uncertain. | | 2 | The Beyonce Rule | "If you liked it, shoulda put a test on it." Test everything you value: performance, security, error paths. | | 3 | Test Boundaries and Errors | Every non-trivial change needs: happy path + failure path + edge case. | | 4 | Hermetic Tests | Self-contained, order-independent, no shared mutable state. Each test sets up and tears down its own world. | ### Tier B — Design (write mode: decide HOW to write each test) | # | Principle | Rule | |---|-----------|------| | 5 | Test Behavior, Not Implementation | Assert on observable outcomes (return values, persisted state, API output). If refactoring breaks the test, the test was wrong. | | 6 | Real Over Mock | Prefer: Real > Fake > Spy > Mock. Mock only at external or nondeterministic boundaries. | | 7 | One Behavior Per Test | Each test is a single given/when/then. Test name reads as a sentence describing the behavior. | | 8 | Test State, Not Interactions | Verify WHAT the result is, not HOW the system got there. `verify(mock).called()` is almost always wrong. | | 9 | DAMP Over DRY | Descriptive And Meaningful Phrases. Duplicate freely if it makes each test self-contained and readable. | | 10 | Straight-Line Tests | No conditionals, loops, try/catch, or computed expected values in tests. Every path through a test is the same path. | | 11 | Clear Failure Messages | The failure message alone should tell you what went wrong, at 3 AM, without reading the test code. | ### Tier C — Verification (review mode: decide IF tests are trustworthy) | # | Principle | Rule | |---|-----------|------| | 12 | Deterministic Always | Same code + same test = same result. Control time, randomness, network, ordering. | | 13 | Tests Are Documentation | Write tests a stranger would want to read while debugging. They document expected behavior. | | 14 | Investigate First-Run Passes | A test that passes immediately proves nothing. Verify it tests the right thing — not the current (possibly buggy) behavior. | | 15 | Survive Refactoring | If refactoring internals breaks a test without changing behavior, that test is testing implementation details. | For code examples, exceptions, and language-specific notes on each principle, see [references/principles.md](references/principles.md). ## Mocking Decision Gate Before adding a mock, answer all five: 1. **Is this dependency external or nondeterministic?** If no, use the real thing. 2. **Will real dependency make the test flaky, slow, or non-hermetic?** If no, use the real thing. 3. **What behavior visibility is lost by mocking here?** Name it explicitly. 4. **Can mocking happen one layer lower while preserving domain behavior?** Push mocks to the edge. 5. **Am I mocking because I understand the dependency, or because I cannot figure out how to use the real one?** Honest self-check. If answers are unclear, do not mock yet. **The hierarchy — prefer left:** ``` Real dependency → Fake (in-memory impl) → Spy (real + recording) → Stub (canned response) → Mock (behavior verification) ``` For framework-specific mocking patterns (Jest, pytest, gomock) and the mock audit checklist, see [references/mocking-guide.md](references/mocking-guide.md). ## AI Oracle Guard **The problem:** AI reads code, infers "expected" behavior from it, writes a test matching the current (possibly buggy) output. 68% of AI-generated test suites validate bugs this way. **The protocol (mandatory during `write` mode):** 1. **Before writing the test:** State the expected behavior from requirements or spec — not from reading the implementation code. 2. **Write the test** encoding what the code SHOULD do, not what it currently DOES. 3. **Run it against current code.** 4. **If it passes on first run — STOP and investigate:** - Behavior already exists correctly → mark as "verified existing behavior" and continue - Behavior might be wrong → flag for human review with specific concern - Test is too weak (e.g., `toBeDefined()` instead of `toEqual(specificValue)`) → strengthen assertion 5. **If it fails** → proceed with implementation (this is the expected TDD path) The test must encode what the code SHOULD do, not what it DOES do. ## Anti-Pattern Quick Reference | # | Pattern | Signal | Fix | |---|---------|--------|-----| | 1 | Mock behavior testing | Assertions on `*-mock` artifacts only | Assert real system outputs | | 2 | Over-mocking | Setup larger than assertion intent | Mock only external boundaries | | 3 | Unrealistic fixtures | Partial objects, impossible state | Contract-complete fixtures | | 4 | Test-only production methods | `resetForTests`, `destroyForTest` | Move to test harness | | 5 | Implementation-detail assertions | Private method call checks | Assert observable outcomes | | 6 | Snapshot overreach | Huge snapshots as primary signal | Assert critical fields explicitly | | 7 | Flaky async/time tests | sleep-based waits, race conditions | Control clock, wait on conditions | | 8 | Silent failures | `expect(true).toBe(true)`, catch-ignore | Fail loudly with diagnostics | | 9 | Skip debt | Skipped tests without tracking | Skip only with reason + ticket | | 10 | Coverage theater | High line coverage, weak behavior coverage | Prioritize branch decisions and invariants | | 11 | Missing regression tests | Bug fixed without pinning failure | Add regression test with fix | | 12 | Missing boundary contracts | Only unit mocks around APIs | Add integration/contract tests | | 13 | Assertion roulette | Multiple unrelated assertions, no clear failure message | One behavior per test, clear messages | | 14 | Circular oracle | Test validates current behavior, not correct behavior | State expected behavior first (Oracle Guard) | | 15 | Conditional test logic | if/else, loops, try/catch in test body | Straight-line code only | For full details with code examples, signals, and corrections, see [references/anti-patterns.md](references/anti-patterns.md). ## Workflow ### Plan Mode - [ ] **Build risk map:** Identify behaviors changed, affected user paths, high-risk failure modes (data loss, auth, money, security, concurrency). - [ ] **Apply Testing Trophy:** Select test levels using the decision heuristic. - [ ] **Define minimum test depth** before writing any tests. - [ ] **Apply Tier A principles** (P1-P4: Mostly Integration, Beyonce Rule, Boundaries, Hermetic). ### Write Mode - [ ] **Define observable outcomes:** Return values, persisted state, emitted events, API output, user-visible behavior. - [ ] **For each non-trivial change:** Write one happy path + one failure path + one boundary/edge case. - [ ] **For bug fixes:** Include a regression test that fails before the fix. - [ ] **Oracle Check (mandatory):** Run each test against current code. If it passes on first run, follow the Oracle Guard protocol above. - [ ] **DAMP structure:** Keep tests descriptive, self-contained, straight-line. Each test tells a complete story. - [ ] **Clear failure messages:** Every assertion failure should identify what went wrong without reading the test source. - [ ] **Apply Tier B principles** (P5-P11). ### Review Mode - [ ] **Anti-pattern scan:** Check each test against the anti-pattern catalog. - [ ] **Mutation smell check:** For each assertion, ask: "Would this test still pass if the value were wrong by 1, null, or empty string?" If yes, the assertion is too weak. - [ ] **Refactoring resilience check:** "Would refactoring internals break this test without changing behavior?" If yes, it tests implementation details. - [ ] **Determinism check:** Identify time, randomness, network, or ordering dependencies. - [ ] **Apply Tier C principles** (P12-P15). ### Report Mode Use the Required Output Template exactly. Include all fields, no omissions. ### Run Order When executing tests, run in layers: 1. Targeted tests for changed area 2. Broader package/module suite 3. Full suite when feasible before handoff ## Completion Gate Do not mark complete until all are true: - [ ] Tests updated for all changed behavior - [ ] Failure/edge coverage added for risky paths - [ ] Oracle Check passed (no unexplained first-run passes) - [ ] Targeted tests executed successfully - [ ] Broader/full execution done or explicitly deferred with reason - [ ] Report includes concrete evidence and limitations ## Honesty Contract Always include in reports: - Exact command(s) run - Scope (files/suites/packages) - Result summary (passed/failed/skipped) - Whether execution was targeted or full-suite - Environment limits that affected confidence **Required phrases:** - If tests were not run: `I did not run tests.` - If only partial scope ran: `I ran targeted tests only.` - If failures remain: `Tests are currently failing:` followed by the list. - If first-run passes were investigated: `I accepted N first-run passing tests after investigation.` **Forbidden phrases:** "should pass", "looks good", "probably fixed", "ready" — without evidence. ## Required Output Template ```text Testing Summary - Mode: <plan|write|review|report> - Commands run: - <command> - Scope: - <files/suites> - Results: - <N passed, M failed, K skipped> - Oracle Check: - <N tests investigated for first-run pass, M verified, K flagged> - Risks covered: - <behaviors validated> - Gaps / limitations: - <what was not verified> ``` ## Integration with Other Skills - **Required:** `test-driven-development` for the RED-GREEN-REFACTOR cycle - **Complementary:** `systematic-debugging` for investigating test failures - **Referenced by:** `authoring-skills` for testing skills ## Bottom Line Evidence is the product. If evidence is weak, improve tests. If evidence is missing, say so directly. If a test passed on first run, prove it should have.
在 GitHub 查看