Skip to content
Development
Skill

/test-driven-development

Core TDD philosophy and testing principles. Use when writing tests interactively or need testing guidance. Emphasizes tests as contracts, mock boundaries not internals, and implementation fixes over test changes.

From plugin
opinionated-claude-skills
919 skills3 agents

Claude Code

$ npx -y skills add Pyroxin/opinionated-claude-skills --skill test-driven-development --agent claude-code

SKILL.md

test-driven-development.SKILL.md
name: test-driven-development
description: Core TDD philosophy and testing principles. Use when writing tests interactively or need testing guidance. Emphasizes tests as contracts, mock boundaries not internals, and implementation fixes over test changes.

Test-Driven Development

**For system-level design principles and architectural boundaries, see the `software-engineer` skill.**

Core Philosophy

<core_philosophy> **Foundation**: TDD is an application of contract-based design. Tests define the contract an implementation must fulfill—they are specifications, not afterthoughts. This connects directly to the abstraction principles in the `software-engineer` skill.

**Tests = Contracts**: Tests represent business requirements and expected behavior. They are contracts the implementation must fulfill. Never compromise test integrity to achieve green tests.

**Tests are source of truth**: When tests fail, fix the implementation. Only change tests when requirements change or test has a verified bug. </core_philosophy>

Testing Approach

Architectural Boundaries and Mocking Strategy

<architectural_boundaries> **Identify architectural boundaries** in your system:

  • Layer boundaries (e.g., data layer, service layer, presentation layer)
  • Module boundaries (e.g., namespaces, packages, crates)
  • Process boundaries (e.g., Erlang processes, Elixir GenServers)
  • External system boundaries (e.g., APIs, databases, third-party services)

</architectural_boundaries>

<unit_definition> **What constitutes a "unit":**

A "unit" is a cohesive component at an architectural boundary:

  • Classes (e.g., Java, Python, Swift)
  • Namespaces with related functions (e.g., Clojure, Haskell)
  • Modules with related predicates (e.g., Prolog)
  • Processes/GenServers (e.g., Erlang, Elixir)
  • Modules with traits/protocols (e.g., Rust, Swift)

</unit_definition>

<mocking_rules> **When to mock:**

  • Mock dependencies **across** architectural boundaries
  • External dependencies injected/passed into system under test get mocked

**When NOT to mock:**

  • Don't mock the system under test itself
  • Don't mock **within** a cohesive unit (e.g., private methods, internal helpers)
  • If tempted to mock internals, that's a design smell — refactor instead

</mocking_rules>

<test_balance> **Balance unit and integration tests:**

  • **Unit tests**: Test each component in isolation with mocked dependencies across boundaries
  • **Integration tests**: Test behavior across boundaries with real implementations
  • Both are necessary — unit tests verify component logic, integration tests verify system behavior
  • Over-mocked tests validate mocks, not real behavior

</test_balance>

<example> **Layered data store (hexagonal architecture):**

┌───────────────────────────────────────────────────────┐
│                   Application Core                    │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐  │
│  │   Domain    │   │   Service   │   │   Use Case  │  │
│  │   Models    │   │   Layer     │   │   Layer     │  │
│  └─────────────┘   └─────────────┘   └─────────────┘  │
│                                                       │
├───────────────────────BOUNDARY────────────────────────┤
│                                                       │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐  │
│  │  Database   │   │   External  │   │   HTTP      │  │
│  │  Adapter    │   │   API       │   │   Client    │  │
│  └─────────────┘   └─────────────┘   └─────────────┘  │
└───────────────────────────────────────────────────────┘
  • **Unit tests**: Test domain models and service layer with mocked adapters
  • **Integration tests**: Test adapters with real external systems (DB, APIs)
  • **Contract tests**: Verify adapters fulfill the port interface
  • External database gets mocked at adapter boundary, not inside services

</example>

Test Doubles Taxonomy

<test_doubles> **Understanding test double types** aids in communicating test intent. This taxonomy was formalized by Gerard Meszaros in *xUnit Test Patterns* (2007):[^1]

| Type | Purpose | When to Use | |------|---------|-------------| | **Stub** | Returns predetermined values | When behavior doesn't affect test outcome | | **Mock** | Verifies interactions occurred | When the interaction IS the behavior being tested | | **Fake** | Working implementation (simplified) | When real implementation too slow/complex | | **Spy** | Records calls for later verification | When need to verify after execution |

**Key insight**: Overuse of mocks often indicates testing implementation rather than behavior. Prefer stubs when possible; use mocks when interactions are the contract.

[^1]: Gerard Meszaros. 2007. *xUnit Test Patterns: Refactoring Test Code*. Addison-Wesley. </test_doubles>

Test Design Process

<design_steps> **When designing tests:** 1. Identify architectural boundaries in the system 2. Determine what constitutes a "unit" (component, layer, module) 3. Plan unit tests for each unit with dependencies mocked at boundaries 4. Plan integration tests crossing boundaries with real implementations 5. Ensure tests verify usage/requirements, not implementation details </design_steps>

<failure_response> **When test fails:** 1. Read test to understand expected behavior 2. Debug implementation to find why it doesn't meet expectations 3. Fix implementation, never "fix" test to pass </failure_response>

<quality_criteria> **Test quality requirements:**

  • Descriptive names explaining the requirement being checked
  • Readable as documentation of system behavior
  • Plan test cases based on usage, not implementation details
  • Include comprehensive documentation (e.g., Javadoc for JUnit, Sphinx for Python) explaining what test ensures and special considerations
  • Tests can have bugs or enforce wrong behaviors—always assess correctness

</quality_criteria>

Test-Driven Development Workflow

<tdd_cycle> 1. **Write failing tests FIRST** based on requirements (including desired usage pattern

Read more
@pyroxin
Ships withopinionated-claude-skills

This project descends from the personal prompts I'd been keeping for Claude Code prior to the release of skills and plugins. Over time it's also evolved into a sandbox where I figure out what makes Claude reliably good at a task, and find prompts that work.

919 skills3 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
9
Star history of Pyroxin/opinionated-claude-skills on GitHub, a chart by star-history.com

Other skills on opinionated-claude-skills.

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.

skills2w309k
@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,…

ecc2w293k
@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…

react5d252k
@facebook@facebookInstall Skill

Questions about test-driven-development.

Which coding agents can use test-driven-development?
test-driven-development 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.