84 lines
2.9 KiB
Markdown
84 lines
2.9 KiB
Markdown
---
|
|
title: testing-anti-patterns
|
|
type: note
|
|
permalink: opencode-config/skills/test-driven-development/testing-anti-patterns
|
|
---
|
|
|
|
# Testing Anti-Patterns
|
|
|
|
Use this reference when writing/changing tests, introducing mocks, or considering test-only production APIs.
|
|
|
|
## Core Principle
|
|
|
|
Test real behavior, not mock behavior.
|
|
|
|
Mocks are isolation tools, not the subject under test.
|
|
|
|
## Anti-Pattern 1: Testing mock existence instead of behavior
|
|
|
|
**Problem:** Assertions only prove a mock rendered or was called, not that business behavior is correct.
|
|
|
|
**Fix:** Assert observable behavior of the unit/system under test. If possible, avoid mocking the component being validated.
|
|
|
|
Gate check before assertions on mocked elements:
|
|
- Am I validating system behavior or only that a mock exists?
|
|
- If only mock existence, rewrite the test.
|
|
|
|
## Anti-Pattern 2: Adding test-only methods to production code
|
|
|
|
**Problem:** Production classes gain methods used only by tests (cleanup hooks, debug helpers), polluting real APIs.
|
|
|
|
**Fix:** Move test-only setup/cleanup into test utilities or fixtures.
|
|
|
|
Gate check before adding a production method:
|
|
- Is this method needed in production behavior?
|
|
- Is this resource lifecycle actually owned by this class?
|
|
- If not, keep it out of production code.
|
|
|
|
## Anti-Pattern 3: Mocking without understanding dependencies
|
|
|
|
**Problem:** High-level mocks remove side effects the test depends on, causing false positives/negatives.
|
|
|
|
**Fix:** Understand dependency flow first, then mock the lowest-cost external boundary while preserving needed behavior.
|
|
|
|
Gate check before adding a mock:
|
|
1. What side effects does the real method perform?
|
|
2. Which side effects does this test rely on?
|
|
3. Can I mock a lower-level boundary instead?
|
|
|
|
If unsure, run against real implementation first, then add minimal mocking.
|
|
|
|
## Anti-Pattern 4: Incomplete mock structures
|
|
|
|
**Problem:** Mocks include only fields used immediately, omitting fields consumed downstream.
|
|
|
|
**Fix:** Mirror complete response/object shapes used in real flows.
|
|
|
|
Gate check for mocked data:
|
|
- Does this mock match the real schema/shape fully enough for downstream consumers?
|
|
- If uncertain, include the full documented structure.
|
|
|
|
## Anti-Pattern 5: Treating tests as a follow-up phase
|
|
|
|
**Problem:** "Implementation complete, tests later" breaks TDD and reduces confidence.
|
|
|
|
**Fix:** Keep tests inside the implementation loop:
|
|
1. Write failing test
|
|
2. Implement minimum code
|
|
3. Re-run tests
|
|
4. Refactor safely
|
|
|
|
## Quick Red Flags
|
|
|
|
- Assertions target `*-mock` markers rather than behavior outcomes
|
|
- Methods exist only for tests in production classes
|
|
- Mock setup dominates test logic
|
|
- You cannot explain why each mock is necessary
|
|
- Tests are written only after code "already works"
|
|
|
|
## Bottom Line
|
|
|
|
If a test does not fail first for the intended reason, it is not validating the behavior change reliably.
|
|
|
|
Keep TDD strict: failing test first, then minimal code.
|