agentleFS
jkitchinjkitchin/knowhow/skills/development/tdd/SKILL.md

tdd

Skill42 starsChanged 17 days agoMITView on GitHub

Test-Driven Development facilitation using the red-green-refactor cycle. Guides users through writing tests first, implementing minimal code to pass, and refactoring for quality. Use when users want to practice TDD, need help writing tests before code, are developing new features test-first, or want guidance on test structure and implementation. Triggers include 'use TDD,' 'test-driven development,' 'write tests first,' 'red-green-refactor,' or requests to develop functionality with tests.

194 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use capture-learning-tools, design-frontend-dev and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • The-Vibe-CompanySkill

    capture-learning-tools

    Turn technical conversations, bugs, CI failures, review comments,

    Also in 5 projects that use this

  • The-Vibe-CompanySkill

    design-frontend-dev

    Clean Impeccable frontend design skill. Use when the user wants to

    Also in 5 projects that use this

  • tristanphvnSkill

    ketchup-video

    Catch the user up like /keel:ketchup, with a short silent video of slides for what happened and the waiting calls as text under it. Use for /keel:ketchup-video.

    Also in 14 projects that use this

  • jaydubya818Skill

    figure-it-out

    Use when novel or multi-phase work needs an auditable workflow and no narrower playbook fits.

    Also in 54 projects that use this

  • jaydubya818Skill

    principle-laziness-protocol

    Apply when a refactor is adding wrappers or abstractions instead of simplifying.

    Also in 45 projects that use this

  • +2 more from The-Vibe-Company
  • +5 more from jaydubya818

The file

Show its rules and text

We split this skill into the rules it gives an agent

41 rules. 0 are common, 37 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 186 edited versions we read keep these.

  • 37

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write test that specifies that behavior

    line 23
  2. Distinctive:

    Run test to verify it fails for the right reason

    line 24
  3. Distinctive:

    If test passes unexpectedly, test is wrong

    line 25
  4. Distinctive:

    Write minimal code to make test pass

    line 28
  5. Distinctive:

    Don't worry about perfection yet

    line 29
  6. Distinctive:

    Run test to verify it passes

    line 31
  7. Distinctive:

    Run tests after each change to ensure still passing

    line 37
  8. Distinctive:

    Commit when tests are green

    line 40
  9. Distinctive:

    Start cycle again with new test

    line 42
  10. Distinctive:

    Test defines what "done" means

    line 51
  11. Distinctive:

    Don't add features not tested

    line 57
  12. Distinctive:

    Keep tests passing during refactoring

    line 62
  13. Distinctive:

    Run tests after each refactoring step

    line 64
  14. Distinctive:

    After writing test (should fail)

    line 67
  15. Distinctive:

    After writing implementation (should pass)

    line 68
  16. Distinctive:

    After each refactoring step (should stay green)

    line 69
  17. Distinctive:

    Test design and organization

    line 80
  18. Distinctive:

    Assert: - Verify the results

    line 87
  19. Distinctive:

    Public interface: - Test behavior users depend on

    line 104
  20. Distinctive:

    Private implementation details: - Test behavior, not internals

    line 111
  21. Distinctive:

    Framework code: - Test your code, not the framework

    line 114
  22. Distinctive:

    Prefer multiple small tests over one large test

    line 120
  23. Distinctive:

    Self-documenting: - Test shows how code should be used

    line 125
  24. Distinctive:

    Minimal setup: - Only what's needed for this test

    line 126
  25. Distinctive:

    No shared mutable state between tests

    line 132
  26. Distinctive:

    What: Test individual functions/methods in isolation

    line 167
  27. Distinctive:

    What: Test multiple components working together

    line 178
  28. Distinctive:

    What: Test complete user workflows

    line 189
  29. Distinctive:

    Your own code: - Prefer real objects for your code

    line 238
  30. Distinctive:

    Logic being tested: - Don't mock what you're testing

    line 240
  31. Very specific:

    Test files: test_*.py, *_test.py, test-*.el

    line 329
  32. Very specific:

    Test functions: Start with test_ or ert-deftest

    line 330
  33. Very specific:

    Test classes: Test* (if using classes)

    line 331
  34. Distinctive:

    Ensure all tests are green: before starting

    line 344
  35. Distinctive:

    Commit frequently: - When tests pass

    line 347
  36. Distinctive:

    Update test to test behavior instead

    line 361
  37. Distinctive:

    Don't test just to increase coverage

    line 387
  38. Very specific:

    Use scripts/coverage_analyzer.py to identify coverage gaps.

    line 395
  39. Distinctive:

    assets/templates/: Test file templates for multiple languages

    line 408
  40. Distinctive:

    Only refactor when green

    line 432
  41. Distinctive:

    Don't add features

    line 435

“Common” is measured: kept by at least 6 in 10 of the 186 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Test-Driven Development (TDD) Skill

Guide users through disciplined test-first development using the red-green-refactor cycle.

Core TDD Workflow

RED → GREEN → REFACTOR → REPEAT

RED: Write a Failing Test

  1. Identify next small behavior to implement
  2. Write test that specifies that behavior
  3. Run test to verify it fails for the right reason
  4. If test passes unexpectedly, test is wrong

GREEN: Make It Pass

  1. Write minimal code to make test pass
  2. Don't worry about perfection yet
  3. Simplest solution that works
  4. Run test to verify it passes

REFACTOR: Improve the Code

  1. Improve code quality while keeping tests green
  2. Remove duplication
  3. Improve names and structure
  4. Run tests after each change to ensure still passing

REPEAT

  1. Commit when tests are green
  2. Identify next behavior
  3. Start cycle again with new test

TDD Discipline

Critical rules to follow:

Test First (RED Phase)

  • Always write test before implementation
  • Resist urge to write code first
  • Test defines what "done" means
  • See test fail before making it pass

Minimal Implementation (GREEN Phase)

  • Write simplest code to pass
  • Don't over-engineer
  • Don't add features not tested
  • One test at a time

Refactor Only When Green

  • Never refactor with failing tests
  • Keep tests passing during refactoring
  • Small, incremental improvements
  • Run tests after each refactoring step

Run Tests Frequently

  • After writing test (should fail)
  • After writing implementation (should pass)
  • After each refactoring step (should stay green)
  • Before committing

When to Use This Skill

Activate for requests involving:

  • "Use TDD for..." / "Test-driven development..."
  • "Write tests first..." / "Red-green-refactor..."
  • Developing new features test-first
  • Learning TDD practices
  • Setting up test infrastructure
  • Test design and organization

Test Structure Patterns

Arrange-Act-Assert (AAA)

Arrange - Set up test data and environment Act - Execute the code under test Assert - Verify the results

def test_add_two_numbers():
    calculator = Calculator()           # Arrange
    result = calculator.add(2, 3)      # Act
    assert result == 5                  # Assert

Given-When-Then (BDD Style)

Given - Initial context/preconditions When - Action/event occurs Then - Expected outcome

Test Design Principles

What to Test

  • Public interface - Test behavior users depend on
  • Edge cases - Boundaries, empty inputs, max values
  • Error conditions - Invalid inputs, exceptions
  • Business logic - Core algorithms and rules
  • Integration points - Where components interact

What NOT to Test

  • Private implementation details - Test behavior, not internals
  • Third-party libraries - Trust they work, test your usage
  • Simple getters/setters - Unless they have logic
  • Framework code - Test your code, not the framework

One Behavior Per Test

  • Each test should verify single behavior
  • Makes failures easier to diagnose
  • Keeps tests focused and readable
  • Prefer multiple small tests over one large test

Make Tests Readable

  • Descriptive names - test_add_returns_sum_of_two_positive_numbers
  • Clear structure - AAA or Given-When-Then
  • Self-documenting - Test shows how code should be used
  • Minimal setup - Only what's needed for this test

Keep Tests Independent

  • Tests should not depend on each other
  • Tests can run in any order
  • Each test starts with clean state
  • No shared mutable state between tests

See references/test-design-patterns.md for comprehensive guidance.

Language-Specific Guidance

For Python

See references/python-tdd.md for:

  • pytest and unittest frameworks
  • Fixtures and parametrized tests
  • Mocking with unittest.mock
  • Testing async code
  • Coverage with pytest-cov
  • Running and organizing tests

For Emacs Lisp

See references/elisp-tdd.md for:

  • ERT (Emacs Lisp Regression Testing)
  • Testing interactive functions
  • Buffer manipulation testing
  • Mocking with cl-letf
  • Buttercup (BDD alternative)
  • Running tests in Emacs and batch mode

For Other Languages

See references/general-tdd.md for:

  • Finding testing frameworks
  • Universal test patterns
  • Common testing concepts
  • Build tool integration
  • Language-agnostic principles

Test Types and When to Use

Unit Tests

What: Test individual functions/methods in isolation

When:

  • Testing pure functions
  • Testing business logic
  • Testing algorithms
  • Fast, focused tests

Example: test_calculate_discount(price, percentage)

Integration Tests

What: Test multiple components working together

When:

  • Testing database interactions
  • Testing API calls
  • Testing service integration
  • Verifying components connect correctly

Example: test_user_service_saves_to_database()

End-to-End Tests

What: Test complete user workflows

When:

  • Testing critical user paths
  • Verifying system as a whole
  • Smoke tests for deployment

Example: test_user_can_register_and_login()

Test Pyramid:

      /\      ← Few E2E tests (slow, brittle)
     /  \
    / IT \    ← Some Integration tests
   /______\
  /  Unit  \  ← Many Unit tests (fast, focused)
 /__________\

TDD Red-Green-Refactor Example

Goal: Implement factorial function

Iteration 1 - Base case:

  • RED: test_factorial_of_zero_is_one() → ❌ factorial not defined
  • GREEN: def factorial(n): return 1 → ✅ Passes
  • REFACTOR: Nothing yet. Commit.

Iteration 2 - Positive numbers:

  • RED: test_factorial_of_five() expects 120 → ❌ Got 1
  • GREEN: Implement loop to calculate factorial → ✅ Passes
  • REFACTOR: Use recursion for elegance → ✅ Still passes. Commit.

Iteration 3 - Error handling:

  • RED: test_factorial_negative_raises_error() → ❌ No error raised
  • GREEN: Add if n < 0: raise ValueError → ✅ All tests pass
  • REFACTOR: Add docstring → ✅ Still passes. Commit.

Done! Function is complete, fully tested, documented. Three test-driven iterations.

Mocking and Test Doubles

When to Mock

  • External dependencies - Databases, APIs, file systems
  • Slow operations - Network calls, large computations
  • Unpredictable behavior - Random, time-dependent, external state
  • Hard to trigger scenarios - Error conditions, edge cases

When NOT to Mock

  • Your own code - Prefer real objects for your code
  • Simple objects - Data classes, value objects
  • Logic being tested - Don't mock what you're testing

Types of Test Doubles

Mock - Programmed with expectations, verifies interactions Stub - Provides canned responses, doesn't verify Fake - Working implementation, simpler than real Spy - Records calls, allows verification after

See references/test-design-patterns.md for detailed mocking strategies.

Common TDD Anti-Patterns

Don't:

❌ Write implementation before test - Defeats TDD purpose

❌ Write multiple tests before making them pass - Stay in rhythm (one test, make it pass, next test)

❌ Refactor with red tests - Only refactor when green

❌ Test implementation details - Test behavior, not internals

❌ Skip refactor step - Technical debt accumulates

❌ Write tests that are hard to understand - Tests are documentation

❌ Create dependencies between tests - Tests must be independent

❌ Mock everything - Use real objects when practical

❌ Fake it with hardcoded values forever - "Fake it till you make it" is temporary

❌ Write slow tests - Slow test suite won't be run frequently

Test Naming Conventions

Good test names are descriptive and specific:

Pattern: test_<function>_<scenario>_<expected_result>

test_add_two_positive_numbers_returns_sum()
test_add_with_negative_number_returns_correct_result()
test_add_with_zero_returns_other_number()

Pattern: should_<expected_behavior>_when_<condition>

should_return_empty_list_when_no_items_match()
should_raise_error_when_input_is_null()
should_calculate_discount_when_user_is_premium()

Pattern: <behavior>_<state>_<expected>

(ert-deftest save-buffer-modified-saves-to-file ())
(ert-deftest load-file-missing-raises-error ())

Test name should:

  • Describe what's being tested
  • Describe the scenario/condition
  • Describe expected outcome
  • Be readable as documentation

Test Organization

Directory Structure

Python:

project/
├── src/
│   └── calculator.py
└── tests/
    ├── __init__.py
    ├── test_calculator.py
    └── conftest.py  # pytest fixtures

Elisp:

package/
├── my-package.el
└── test/
    └── test-my-package.el

Naming Conventions

  • Test files: test_*.py, *_test.py, test-*.el
  • Test functions: Start with test_ or ert-deftest
  • Test classes: Test* (if using classes)

Grouping Tests

  • One test file per source file (generally)
  • Group related tests in same file
  • Separate unit/integration/e2e tests

See language-specific references for detailed organization patterns.

Refactoring with Tests

Safe Refactoring Process

  1. Ensure all tests are green before starting
  2. Make small changes - One refactoring at a time
  3. Run tests after each change - Catch breaks immediately
  4. Commit frequently - When tests pass
  5. Don't add features while refactoring - Separate concerns

Common Refactorings

  • Extract function (break up large functions)
  • Rename for clarity
  • Remove duplication (DRY)
  • Simplify conditional logic
  • Extract variable for readability
  • Inline unnecessary abstraction

When Tests Break During Refactoring

If test is testing implementation detail:

  • Update test to test behavior instead
  • Make test more resilient to changes

If test is testing behavior:

  • Fix the code, not the test
  • Behavior shouldn't change during refactoring

If too many tests break:

  • Change is too large, revert
  • Make smaller incremental changes

See references/refactoring-with-tests.md for detailed guidance.

Test Coverage

Coverage measures which code is executed by tests, not whether tests are good.

Types of Coverage

  • Line coverage - Which lines executed
  • Branch coverage - Which paths taken
  • Function coverage - Which functions called

Coverage Goals

  • Aim for high coverage (80%+) but not 100%
  • 100% coverage doesn't mean bug-free
  • Focus on critical code paths
  • Don't test just to increase coverage

Using Coverage Tools

  • Python: pytest-cov, coverage.py
  • JavaScript: Jest with coverage
  • Java: JaCoCo
  • Ruby: SimpleCov

Use scripts/coverage_analyzer.py to identify coverage gaps.

Using Supporting Resources

Additional resources in this skill:

  • references/python-tdd.md: Comprehensive Python testing guide (pytest, unittest, mocking, async)
  • references/elisp-tdd.md: Comprehensive Elisp testing guide (ERT, Buttercup, interactive functions)
  • references/general-tdd.md: Universal TDD principles for any language
  • references/test-design-patterns.md: What to test, test organization, anti-patterns
  • references/refactoring-with-tests.md: Safe refactoring process and common refactorings
  • scripts/test_template_generator.py: Generate test file boilerplate
  • scripts/coverage_analyzer.py: Analyze coverage reports
  • assets/templates/: Test file templates for multiple languages

Quick Reference

TDD Cycle:

  1. RED - Write failing test
  2. GREEN - Make it pass (minimal code)
  3. REFACTOR - Improve while keeping green
  4. REPEAT

Test Structure:

  • Arrange (setup)
  • Act (execute)
  • Assert (verify)

Test Principles:

  • Test first
  • One test at a time
  • One behavior per test
  • Independent tests
  • Fast tests
  • Readable tests

Refactoring Rules:

  • Only refactor when green
  • Small changes
  • Run tests frequently
  • Don't add features

Remember: TDD is a discipline. The value comes from following the cycle strictly. Test first. See it fail. Make it pass. Refactor. Repeat. The rhythm creates quality code.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.