BundledSoftware DevelopmentVersion 1.1.0

Test-Driven Development with Hermes Agent: RED-GREEN-REFACTOR

TDD: enforce RED-GREEN-REFACTOR, tests before code.

Written by Neura Market from the official Hermes Agent documentation for Test Driven Development. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

Test-Driven Development (TDD) Reference

Purpose and Scope

This document defines the mandatory test-driven development (TDD) workflow for all production code at Neura Market. The purpose is to ensure production code is only written to make a pre-existing failing test pass, guaranteeing test validity and behavioral correctness.

When to Use TDD

Use TDD always for:

  • New features
  • Bug fixes
  • Refactoring
  • Behavior changes

Exceptions require explicit user permission:

  • Throwaway prototypes
  • Generated code
  • Configuration files

Core Capabilities

  • Forces test-first discipline to validate test correctness.
  • Enforces the Red-Green-Refactor cycle for incremental development.
  • Prevents untested production code via the Iron Law.
  • Detects regressions immediately by running the full test suite after each green step.
  • Guides interface design by making hard-to-test code a signal to simplify.
  • Integrates with agent tools (terminal, delegate_task, systematic-debugging) to automate TDD enforcement.

The Iron Law

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST

This is the foundational rule. No production code is written unless a test exists that has already failed for the expected reason.

Red-Green-Refactor Cycle

This is the core procedure. Follow the ordered steps exactly for each behavior.

Step 1: RED — Write a Failing Test

Write one minimal test for one behavior. Use a clear descriptive name. If the name contains "and", split it into separate tests. Test real code, not mocks unless truly unavoidable.

Example of a good test:

def test_retries_failed_operations_3_times():
    attempts = 0
    def operation():
        nonlocal attempts
        attempts += 1
        if attempts < 3:
            raise Exception('fail')
        return 'success'

    result = retry_operation(operation)

    assert result == 'success'
    assert attempts == 3

Example of a bad test (vague name, tests mock not real code, missing assertions):

def test_retry_works():
    mock = MagicMock()
    mock.side_effect = [Exception(), Exception(), 'success']
    result = retry_operation(mock)
    assert result == 'success'  # What about retry count? Timing?

Step 2: Verify RED

Run the specific test using the terminal tool. Confirm it fails for the expected reason (feature missing, not a typo). If it passes, fix the test. If it errors, fix the error and re-run until it fails correctly.

# Use terminal tool to run the specific test
pytest tests/test_feature.py::test_specific_behavior -v

Step 3: GREEN — Write Minimal Code

Write the simplest code to pass the test. No extra features, refactoring, or improvements. Cheating is allowed (hardcode, copy-paste, duplicate, skip edge cases).

Example of good GREEN code:

def add(a, b):
    return a + b  # Nothing extra

Example of bad GREEN code (extra feature not required by test):

def add(a, b):
    result = a + b
    logging.info(f"Adding {a} + {b} = {result}")  # Extra!
    return result

Step 4: Verify GREEN

Run the specific test to confirm it passes. Then run ALL tests to check for regressions. Output must be pristine (no errors, warnings). If the test fails, fix the code, not the test. If other tests fail, fix regressions now.

# Run the specific test
pytest tests/test_feature.py::test_specific_behavior -v

# Then run ALL tests to check for regressions
pytest tests/ -q

Step 5: REFACTOR — Clean Up

Clean up code (remove duplication, improve names, extract helpers, simplify expressions) while keeping tests green. Do not add behavior. If tests fail, undo immediately and take smaller steps.

Step 6: Repeat

Move to the next failing test for the next behavior. One cycle at a time.

Avoid Horizontal Slices

Do NOT write all tests first then all implementation (horizontal slicing). Instead, use vertical tracer bullets: one RED to GREEN cycle per end-to-end behavior slice. Each cycle proves the path works, teaches about the interface, and grounds the next test in what was just learned.

WRONG:
  RED:   test1, test2, test3, test4
  GREEN: impl1, impl2, impl3, impl4

RIGHT:
  RED→GREEN: test1→impl1
  RED→GREEN: test2→impl2
  RED→GREEN: test3→impl3

When Stuck

  • Don't know how to test: Write the wished-for API, write the assertion first, ask the user.
  • Test too complicated: Design too complicated; simplify the interface.
  • Must mock everything: Code too coupled; use dependency injection.
  • Test setup huge: Extract helpers; if still complex, simplify the design.

Hermes Agent Integration

Using the Terminal Tool

Use the terminal tool at each step to run tests.

# RED — verify failure
terminal("pytest tests/test_feature.py::test_name -v")

# GREEN — verify pass
terminal("pytest tests/test_feature.py::test_name -v")

# Full suite — verify no regressions
terminal("pytest tests/ -q")

Using delegate_task

Enforce TDD in the goal by specifying the TDD cycle and project test command.

delegate_task(
    goal="Implement [feature] using strict TDD",
    context="""
    Follow test-driven-development skill:
    1. Write failing test FIRST
    2. Run test to verify it fails
    3. Write minimal code to pass
    4. Run test to verify it passes
    5. Refactor if needed
    6. Commit

    Project test command: pytest tests/ -q
    Project structure: [describe relevant files]
    """,
    toolsets=['terminal', 'file']
)

Using systematic-debugging

Write a failing test reproducing the bug, then follow the TDD cycle. Never fix bugs without a test.

Parameters

ParameterMeaningRequired
Test nameMust be clear and descriptive, describing behavior not implementation. If name contains 'and', split into separate tests.Yes
Test contentMust test real code, not mocks unless truly unavoidable. One behavior per test.Yes
Test commandCommand to run a specific test (e.g., pytest tests/test_feature.py::test_name -v) and full suite (e.g., pytest tests/ -q).Yes
Production codeCode written only after a failing test exists. Must be minimal to pass the test.Yes

Constraints and Caveats

  • NO production code without a failing test first (Iron Law).
  • If code is written before the test, delete it entirely. Do not keep as reference, adapt, or look at it.
  • Test must be watched fail before implementation. If test passes immediately, it is invalid.
  • During GREEN, do not add features, refactor other code, or improve beyond the test.
  • During REFACTOR, keep tests green throughout. Do not add behavior.
  • If tests fail during refactor, undo immediately and take smaller steps.
  • Do not write all tests first then implement (horizontal slicing). Use vertical tracer bullets.
  • Tests written after code pass immediately and prove nothing. They may test the wrong thing, implementation, or miss edge cases.
  • Manual testing is ad-hoc and not a substitute for automated tests.
  • Deleting hours of work is not wasteful; keeping unverified code is technical debt (sunk cost fallacy).
  • TDD is pragmatic; shortcuts lead to debugging in production.
  • Tests-after answer "what does this do?"; tests-first answer "what should this do?".
  • If a test is hard to write, the design is unclear. Listen to the test.
  • Never fix bugs without a test.
  • Testing anti-patterns: testing mock behavior instead of real, testing implementation details, happy path only, brittle tests.
  • Final rule: Production code to test exists and failed first. Otherwise not TDD. No exceptions without user's explicit permission.
Production code → test exists and failed first
Otherwise → not TDD

Failure Modes

Failure ModeAction
Code before testDelete and restart with TDD.
Test after implementationDelete and restart with TDD.
Test passes immediately on first runFix the test.
Can't explain why test failedDelete and restart with TDD.
Tests added 'later'Delete and restart with TDD.
Rationalizing 'just this once'Delete and restart with TDD.
'I already manually tested it'Delete and restart with TDD.
'Tests after achieve the same purpose'Delete and restart with TDD.
'Keep as reference' or 'adapt existing code'Delete and restart with TDD.
'Already spent X hours, deleting is wasteful'Delete and restart with TDD.
'TDD is dogmatic, I'm being pragmatic'Delete and restart with TDD.
'This is different because...'Delete and restart with TDD.
Test fails during GREENFix code, not test.
Other tests fail during GREENFix regressions now.
Test errors during REDFix error, re-run until it fails correctly.
Output not pristine (errors, warnings)Fix before marking complete.

Prerequisites

  • User's explicit permission required for exceptions (throwaway prototypes, generated code, configuration files).
  • Project test command must be known (e.g., pytest tests/ -q).
  • Project structure must be understood for file operations.
  • Ability to run tests via the terminal tool.
  • For delegate_task: context must include TDD instructions and project test command.

Skills the docs pair this with

More Software Development skills