Skip to content
Development
Skill

/testing-philosophy

Use when proposing, writing, or reviewing automated tests, defines what a good test is: behavior over implementation details, and the Testing Trophy with a hard floor on end-to-end coverage for user-facing features. Generalized to any language and any layer (frontend, backend,

From plugin
agent-skills
1240 skills

Claude Code

$ npx -y skills add Flagrare/agent-skills --skill testing-philosophy --agent claude-code

SKILL.md

testing-philosophy.SKILL.md
name: testing-philosophy
description: "Use when proposing, writing, or reviewing automated tests, defines what a good test is: behavior over implementation details, and the Testing Trophy with a hard floor on end-to-end coverage for user-facing features. Generalized to any language and any layer (frontend, backend, CLI, library), not just JS/React. REQUIRED BACKGROUND for skills that plan or review tests, atdd-plan, implementation-review, tdd-writer, wrap-up. Use when the user asks whether tests are good, what to test, why a test is brittle, or whether e2e is needed."

Testing philosophy

This is the shared definition of "good test" that every flagrare skill which proposes or reviews tests leans on. It distils Kent Dodds' testing writing and generalizes it past his JS/React context to any language and any layer. (Grounded in [`docs/research/2026-06-11-kent-dodds-testing-philosophy.md`](../../../../docs/research/2026-06-11-kent-dodds-testing-philosophy.md).)

The one principle

> **The more your tests resemble the way your software is used, the more confidence they can give you.** (Kent C. Dodds)

Every rule below is a corollary. The principle is already language- and layer-agnostic; "the way your software is used" just resolves to a different surface in each context. When a testing decision is unclear, return to this sentence.

Pillar 1: Behavior over implementation details

An **implementation detail** is anything *"users of your code will not typically use, see, or even know about."* A test bound to one fails in both directions at once:

  • **False negative on refactor**: you change internals without changing behavior, and the test breaks anyway. It cries wolf.
  • **False positive on breakage**: you break the actual behavior, and the test stays green because it was watching the mechanism, not the result.

Dodds' framing: a test that drives your code differently from how real users drive it becomes *a third user you never wanted*, now you have to keep the end user, the calling developer, **and** the test happy.

**"User" generalizes by layer.** Assert only on what *that* user can observe; drive the code only through the surface *that* user touches:

| Layer | The user | Assert on (observable) | Do NOT touch (implementation) | |---|---|---|---| | Library / module | the calling developer | return values, thrown errors, public types, emitted events | private fields/methods, internal helpers, internal data-structure choices | | Backend / API | the HTTP/RPC client | status codes, response bodies, headers, state visible *through* the API, domain events | ORM internals, service method names, query shapes, internal DTOs | | Frontend / UI | the person clicking | rendered text, roles, what appears/disappears after an interaction | component state vars, hook internals, CSS class names, child-component names | | CLI | the person at the prompt | stdout/stderr, exit code, files written | internal flag parsing, function call order |

**Concrete tells of an implementation-detail test** (stack-independent, flag any of these):

  • Asserts on private fields, unexported functions, internal state, or internal data-structure shape.
  • Asserts a particular internal function/method *was called*, spy / mock-call-count assertions on a collaborator **you own**.
  • Mocks a collaborator you own, rather than mocking only at a true external boundary (network, disk, clock, OS process, third-party service).
  • Its name describes a mechanism (`calls setIndex with 0`) instead of a behavior (`shows the first slide on load`).

**The acid test:** *"If I refactor the internals but keep the public contract identical, does this test break?"* If yes, it tests the wrong thing. Pair it with: *"Does this assert what a real user observes?"* If no, same problem.

Pillar 2: The Testing Trophy, and the e2e floor

Four layers, bottom to top. Height is **confidence**; height is also **cost/time**. Testing is "return on investment where return is confidence and investment is time."

| Layer | What it is | Mock how much | |---|---|---| | **Static** | types + lint, correctness for free | n/a | | **Unit** | one piece in isolation | dependencies mocked | | **Integration** | several units working together, **the default tier** | mock only external boundaries | | **E2E** | the whole assembled system | "as little as possible" |

"Write tests. Not too many. **Mostly integration**" puts most effort in the middle, because that's the best confidence-per-effort and most regressions live *between* units, not inside them.

**The correction that matters: "mostly integration" is not "skip e2e."** There are two opposite violations, and most reviews only catch the first:

1. **Too much e2e**: every scenario duplicated as a slow, flaky full-stack test that could be an integration test. Flag it; push it down the trophy. 2. **No e2e at all for the critical path**: every layer tested in isolation, but nothing proves they connect. This is the quieter, more common gap. Flag it just as hard.

**The e2e necessity rule:** *every user-facing feature needs at least one end-to-end (or highest-practical) test that exercises its critical happy path through the real, assembled system*, one or two paths, not one per scenario. The e2e tier proves the wiring; integration proves the behavior; unit proves the tricky pure logic; static proves the shapes. A plan or a diff that has unit + integration coverage but no wiring proof for a user-facing feature **has a gap**.

**E2e does not require a browser**: it generalizes:

| Surface | What "e2e" means | |---|---| | Frontend app | browser-driven test of the critical journey: load → act → see the result | | Backend service | hit the running service over HTTP against a real (test) DB; assert response + persisted state | | CLI | invoke the built binary as a subprocess; assert stdout / exit code / files written | | Library | consume the published public API exactly as a downstream user would, nothing internal stubbed |

Read more
@flagrare
Ships withagent-skills

Thirty-eight skills that wrap around your development cycle in Claude Code. They turn tickets into ATDD plans, smoke-test features against a running app or service, hunt down bugs with runtime evidence, guard commits against doc drift, run seven-axis code

Stars on GitHub

Momentum

stars in total
12
Star history of Flagrare/agent-skills on GitHub, a chart by star-history.com

Other skills on agent-skills.

atdd-plan

atdd-plan

Produce an ATDD-first implementation plan in Claude Code's native plan mode, with named design patterns called out where they…

brag-doc

brag-doc

Generate a comprehensive, impact-framed brag-doc entry for a chosen time window (day, week, biweek, month, or custom). Pulls…

bug-bash

bug-bash

Programmatic bug bashing, ingest a prescribed test plan (Notion, markdown, pasted spec), drive a real running system (browser via…

career

career

Run the career skills that are due, in one pass, and return one short combined digest plus an updated board. It reads timestamps…

codebase-explore

codebase-explore

Explore the codebase to map conventions, reusable utilities, analogous features, and data flows relevant to a planned change.…

daily-code-review

daily-code-review

Generate a daily code review report showing stale PRs, items needing your attention, and active work for your team. Use whenever…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about testing-philosophy.

Which coding agents can use testing-philosophy?
testing-philosophy installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.