test-driven-development
Test-Driven Development
Write tests before code. The test is the specification. If you can't write a test, you don't understand the requirement.
Related Skills:
kavak-documentation- Query for Kavak-specific testing patterns, kbroker event testing, STS mocking- Use
kavak-platform/platform_docs_searchMCP tool for testing best practices at Kavak
Quick Start
# 1. Write failing test first
# 2. Run to see it fail (RED)
# 3. Write minimal code to pass (GREEN)
# 4. Refactor while tests pass (REFACTOR)
# 5. Repeat
Test commands by language:
| Language | Run Tests | Watch Mode |
|---|---|---|
| Go | go test ./... |
go test ./... -v |
| Node/TS | npm test |
npm test -- --watch |
| Python | pytest |
pytest-watch |
| Java | ./mvnw test |
./mvnw test -Dtest=* |
The Red-Green-Refactor Cycle
1. RED: Write Failing Test
- Write ONE test for the next piece of behavior
- Test must fail for the RIGHT reason
- Use descriptive names: should_calculate_total_with_tax
- Follow Arrange-Act-Assert structure
2. GREEN: Make It Pass
- Write MINIMAL code to pass the test
- Don't optimize, don't refactor, don't add features
- "Fake it till you make it" is valid
- The goal is GREEN, not perfect
3. REFACTOR: Improve Design
- Clean up code while tests stay green
- Remove duplication
- Improve names
- Extract methods/functions
- Run tests after EVERY change
Common Rationalizations (Resist Them)
| Rationalization | Counter |
|---|---|
| "Let me just write one more method" | Stop. Test what exists first |
| "I'll add tests after" | You won't. Tests written after verify nothing |
| "It's too simple to test" | Simple now, complex later. Test it |
| "I'll refactor tests later" | Refactor production code, not test structure |
| "This is just scaffolding" | Scaffolding becomes foundation. Test it |
Anti-Patterns (What NOT to Do)
| Anti-Pattern | Problem | Fix |
|---|---|---|
| The Liar | Test passes but tests nothing | Assert actual behavior |
| The Mockery | Over-mocking hides real bugs | Mock boundaries only |
| Excessive Setup | 50 lines setup, 2 lines test | Simplify SUT or use builders |
| The Slow Poke | Tests take minutes | Isolate, mock I/O |
| The Local Hero | Passes locally, fails in CI | No env dependencies |
| Test-per-Method | 1:1 test-to-method | Test behaviors, not methods |
Verification Checklist
Before committing, verify your tests:
[ ] Test fails when behavior is removed?
[ ] Test name describes the behavior?
[ ] Arrange-Act-Assert structure clear?
[ ] No test-only code in production?
[ ] Mocks verify behavior, not implementation?
[ ] Edge cases covered?
When TDD Is Mandatory
- New features (write test first)
- Bug fixes (write failing test that reproduces bug)
- Refactoring (tests protect behavior)
- API changes (contract tests first)
When to Adapt TDD
- Exploratory/spike work (delete code after, then TDD)
- UI prototyping (test logic, not layout)
- Legacy code (add tests before changing)
Test Naming Convention
should_[expected_behavior]_when_[condition]
Examples:
- should_return_zero_when_cart_is_empty
- should_throw_error_when_user_not_found
- should_apply_discount_when_coupon_valid
References
| Reference | Purpose |
|---|---|
references/red-green-refactor.md |
Detailed cycle walkthrough |
references/anti-patterns.md |
Full anti-pattern catalog |
references/examples-go.md |
Go TDD examples |
references/examples-node.md |
Node/TypeScript TDD examples |
references/examples-python.md |
Python TDD examples |
references/examples-java.md |
Java TDD examples |
references/verification-checklist.md |
Pre-commit verification |
references/testing-boundaries.md |
What to mock, what not to mock |
Best Practices
- One assertion per test - Multiple assertions hide failures
- Test behavior, not implementation - Tests survive refactoring
- Isolated tests - No shared state between tests
- Fast tests - Under 100ms per unit test
- Deterministic - Same result every run
- Self-documenting - Test name = specification
Principle: If you can't write a test for it, you don't understand what it should do. The test IS the specification.
More from carvalab/k-skills
code-review
Use this skill as the FINAL step after writing or modifying code — reviews for logic bugs, architecture violations, security issues, and performance problems. Trigger after completing a feature, fixing a bug, before merging, or when asked to "review this code", "check my changes", or "is this ready to merge". Fixes issues directly and runs quality gates (lint, typecheck, build, tests). Delegates style to automation, focuses on what matters.
38refactor-cleaner
Use this skill to find and remove dead code, unused dependencies, duplicate logic, and unused exports using detection tools (knip, depcheck, ts-prune, deadcode, staticcheck). Trigger on "clean up dead code", "remove unused", "find dead code", "reduce bundle size", "dependency audit", or when the codebase feels bloated. For simplifying living code (readability, naming, complexity reduction) without detection tools, use code-simplifier instead. Use this skill during maintenance windows or before major refactors.
36code-simplifier
Use this skill after writing or modifying code to simplify it — reduces complexity, eliminates redundancy, and improves naming while preserving exact behavior. Trigger after implementing a feature, after a refactor, or when asked to "clean up this code", "simplify this", "make this more readable", or "reduce complexity". Also use when code feels too nested, verbose, or hard to follow. For removing dead code and unused dependencies with detection tools (knip, ts-prune, deadcode), use refactor-cleaner instead.
24backend-development
Use this skill for ANY task in a Node.js/TypeScript or Go backend codebase — adding features, fixing bugs, refactoring, adding flows, modifying handlers, changing business logic, or writing new code. Trigger even when the task is vague like "add the flow to this", "implement this feature", "fix this", or "add X like Y" — if the project has go.mod, nest-cli.json, express routes, or server-side TypeScript, this skill applies. Covers REST APIs, PostgreSQL, Redis, authentication, job queues, events, microservices, Docker, CI/CD, Clean Architecture, SOLID, DRY, and code reuse patterns. When in doubt whether this is backend work, use this skill.
24doc-updater
Use this skill when documentation needs updating — after adding features, changing APIs, modifying architecture, or updating dependencies. Trigger on "update the docs", "generate codemap", "refresh the README", "document this", "update architecture docs", or when code changes make existing documentation stale. Generates codemaps from actual code, updates READMEs, architecture diagrams, and guides.
22frontend-development
Use this skill for ANY task in a Next.js or React frontend codebase — adding pages, building components, fixing UI bugs, styling, handling forms, fetching data, or modifying layouts. Trigger even when the task is vague like "add this feature", "fix the UI", "make this page", or "update the form" — if the project has next.config.*, React components, or client-side TypeScript, this skill applies. Covers App Router, Server Components, Server Actions, MUI styling, Zod validation, caching, and design quality. When in doubt whether this is frontend work, use this skill.
21