principle-test-behavior-not-implementation

Rewrites or deletes tests that assert implementation details instead of observable behavior.

2|Updated Jun 27, 2026
One-click install
npx skills add https://github.com/imjasonh/playground --skill principle-test-behavior-not-implementation-imjasonh
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: principle-test-behavior-not-implementation
Source: https://github.com/imjasonh/playground/tree/main/.cursor/skills/principle-test-behavior-not-implementation
Command: npx skills add https://github.com/imjasonh/playground --skill principle-test-behavior-not-implementation-imjasonh

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Test suites accumulate tests that cannot fail for a defect: weak assertions, mock-call checks, constant pins, and self-referential comparisons. These tests cost CI time and review attention while catching nothing, and constant pins actively block legitimate edits. ## Core Features & Use Cases - Dead-Test Detection: Applies a single check—would the test still pass if every imported function returned undefined—to identify tests that observe no behavior. - Five Anti-Pattern Catalog: Recognizes weak assertions, mock-or-absence-only checks, self-referential expectations, constant pins, and fixture-asserts-fixture shapes. - Concrete Rewrite Guidance: Shows how to fix each shape by calling the subject with one concrete input and asserting a literal output, such as expect(slugify("Hello, World!")).toBe("hello-world"). - Use Case: While reviewing a pull request, apply the undefined-return check to each new test, rewrite assertions that restate constants or only verify mock calls, and delete tests with no behavioral assertion. ## Quick Start Review the tests in this change and rewrite or delete any that would still pass if every imported function returned undefined.

Frequently Asked Questions about principle-test-behavior-not-implementation

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I test behavior instead of implementation in unit tests?▼

Call the code the way its users do and assert the observable result against a literal expected value, such as expect(slugify("Hello, World!")).toBe("hello-world"). Avoid asserting which internal calls were made or restating constants the code contains.

How to tell if a unit test is useless?▼

Ask whether the test would still pass if every function it imports returned undefined. If yes, it observes no behavior and cannot fail for a defect, so rewrite the assertion or delete the test.

Should I assert that a mock was called with toHaveBeenCalled?▼

Asserting only that a mock was called verifies no behavior. Instead assert the payload the mock received or the state after the call, so the test fails when the code produces a wrong result.

Is it bad to test constants or config values directly?▼

Pinning a constant like expect(LIMITS.maxTools).toBe(8) catches no defect and fails whenever someone legitimately edits the value. Test the mechanism that reads the constant with one concrete input instead of restating the value.

When should I delete a test instead of rewriting it?▼

Delete a test when no behavioral assertion exists for it: when there is no concrete input whose literal output or observable effect the test can check. Keeping it only costs CI time and review attention.

What kinds of non-behavioral tests are worth keeping?▼

Keep tests of a relation across a table's rows, such as a key present in two tables or a parent that exists, and compile-time checks in *.test-d.ts files. These verify real constraints even though they do not call a function's output.