principle-test-behavior-not-implementation
Apply when you write, change, or keep a test. Call the code the way its users do and assert the result they observe against a literal expected value. If the test would still pass when every imported function returns undefined, rewrite the assertion or delete the test.
- License 许可
- MIT
- 最近更新
- 2026-11-11
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- principle-test-behavior-not-implementation
- description
- Apply when you write, change, or keep a test. Call the code the way its users do and assert the result they observe against a literal expected value. If the test would still pass when every imported function returns undefined, rewrite the assertion or delete the test.
- disable-model-invocation
- true
03 SKILL.md 正文
Test Behavior, Not Implementation
A test calls the code the way its users do and asserts the result they observe against a literal expected value. A test that asserts which calls the code made, or restates a constant the code contains, does neither.
The check: before you keep a test, ask whether it would still pass if every function it imports returned undefined. If yes, it observes no behavior and cannot fail for a defect. Rewrite the assertion or delete the test.
Why: A test that cannot fail for a defect costs CI time and review attention and catches nothing. A constant pin also fails when someone edits the constant or the prompt it restates, so it prevents that edit.
Five shapes that still pass when every imported function returns undefined:
- Weak or no assertion. No
expect, or onlytoBeDefined,toBeTruthy,not.toThrow,toBeInstanceOf,toBeGreaterThan(0). - Mock or absence only. Only
toHaveBeenCalled,not.toHaveBeenCalled,toBeUndefined,toEqual([]),toHaveLength(0),not.toBe(wrongValue). - Self-referential. The expected value comes from the code under test:
expect(f(a)).toBe(f(a)),expect(parsed.url).toBe(buildUrl(...)). - Constant pin. The assertion restates a hand-maintained constant, config default, table row, or prompt string:
expect(LIMITS.maxTools).toBe(8),expect(PROMPT).toContain("You are"). - Fixture asserts fixture. The assertion reads data the test built or a value computed in
beforeEach, and the subject never runs inside the body.
The fix: call the subject inside the test body with one concrete input and assert the literal output or the observable effect, expect(slugify("Hello, World!")).toBe("hello-world"). For an absence, assert the presence on the other input in the same test. For a constant, test the mechanism that reads it with one input instead of restating the value. For a mock, assert the payload it received or the state after the call, not that it was called. When no such assertion exists, delete the test.
Keep a test of a relation across a table's rows (a key present in two tables, a parent that exists), and a compile-time check in a *.test-d.ts file.
04 同仓库更多 Skills
why
Use for 'why does X work this way', 'why we picked Y', design rationale, regressions, postmortems, or data-backed thresholds. Discovers available MCPs and queries each evidence category (source control, issue tracker, long-form docs, real-time chat, infrastructure observability, error tracking, product analytics warehouse) in parallel, then returns a cited read on decisions and tradeoffs. Use how for runtime behavior.
unslop
Cut AI tells from any writing. Must always apply.
typescript-best-practices
TypeScript best practices. Use when reading or editing any .ts or .tsx file.
technical-writing
Layered technical-writing standard: Diátaxis structure, Google developer style sentences, STE instruction rules, Global English syntax. Use for /technical-writing or when writing or reviewing docs, RFCs, readmes, PR descriptions, or commit messages.
teach
Explain a body of work plainly so a person actually understands it. Runs the `how` and `why` skills and weaves what they find into one clear explanation. Use for 'teach me this', 'help me really understand X', 'explain this change or subsystem to me'.
tdd
Use only when the user explicitly asks for TDD, a failing test, or a regression test, OR when the bug has an obvious cheap local test target. Skip when the test path is unclear, expensive, integration-heavy, or not requested.