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
Install
$ npx -y skills add Pyroxin/opinionated-claude-skills --skill test-driven-development --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/test-driven-development

Context preview

The summary Claude sees to decide when to auto-load this skill.

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.

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
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.

Get the whole plugin

Other skills on opinionated-claude-skills.