Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when writing or changing tests, adding mocks, or tempted to add test-only methods to production code - prevents testing mock behavior, production pollution with test-only methods, and mocking without understanding dependencies
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 159% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 90% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 114% | 0% |
Tests must verify real behavior, not mock behavior. Mocks are a means to isolate, not the thing being tested.
Core principle: Test what the code does, not what the mocks do.
Following strict TDD prevents these anti-patterns.
1. NEVER test mock behavior
2. NEVER add test-only methods to production classes
3. NEVER mock without understanding dependenciesThe violation:
typescript// ❌ BAD: Testing that the mock exists test('renders sidebar', () => { render(<Page />); expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument(); });
Why this is wrong:
your human partner's correction: "Are we testing the behavior of a mock?"
The fix:
typescript// ✅ GOOD: Test real component or don't mock it test('renders sidebar', () => { render(<Page />); // Don't mock sidebar expect(screen.getByRole('navigation')).toBeInTheDocument(); }); // OR if sidebar must be mocked for isolation: // Don't assert on the mock - test Page's behavior with sidebar present
BEFORE asserting on any mock element:
Ask: "Am I testing real component behavior or just mock existence?"
IF testing mock existence:
STOP - Delete the assertion or unmock the component
Test real behavior insteadThe violation:
typescript// ❌ BAD: destroy() only used in tests class Session { async destroy() { // Looks like production API! await this._workspaceManager?.destroyWorkspace(this.id); // ... cleanup } } // In tests afterEach(() => session.destroy());
Why this is wrong:
The fix:
typescript// ✅ GOOD: Test utilities handle test cleanup // Session has no destroy() - it's stateless in production // In test-utils/ export async function cleanupSession(session: Session) { const workspace = session.getWorkspaceInfo(); if (workspace) { await workspaceManager.destroyWorkspace(workspace.id); } } // In tests afterEach(() => cleanupSession(session));
BEFORE adding any method to production class:
Ask: "Is this only used by tests?"
IF yes:
STOP - Don't add it
Put it in test utilities instead
Ask: "Does this class own this resource's lifecycle?"
IF no:
STOP - Wrong class for this methodThe violation:
typescript// ❌ BAD: Mock breaks test logic test('detects duplicate server', () => { // Mock prevents config write that test depends on! vi.mock('ToolCatalog', () => ({ discoverAndCacheTools: vi.fn().mockResolvedValue(undefined), })); await addServer(config); await addServer(config); // Should throw - but won't! });
Why this is wrong:
The fix:
typescript// ✅ GOOD: Mock at correct level test('detects duplicate server', () => { // Mock the slow part, preserve behavior test needs vi.mock('MCPServerManager'); // Just mock slow server startup await addServer(config); // Config written await addServer(config); // Duplicate detected ✓ });
BEFORE mocking any method:
STOP - Don't mock yet
1. Ask: "What side effects does the real method have?"
2. Ask: "Does this test depend on any of those side effects?"
3. Ask: "Do I fully understand what this test needs?"
IF depends on side effects:
Mock at lower level (the actual slow/external operation)
OR use test doubles that preserve necessary behavior
NOT the high-level method the test depends on
IF unsure what test depends on:
Run test with real implementation FIRST
Observe what actually needs to happen
THEN add minimal mocking at the right level
Red flags:
- "I'll mock this to be safe"
- "This might be slow, better mock it"
- Mocking without understanding the dependency chainThe violation:
typescript// ❌ BAD: Partial mock - only fields you think you need const mockResponse = { status: 'success', data: { userId: '123', name: 'Alice' }, // Missing: metadata that downstream code uses }; // Later: breaks when code accesses response.metadata.requestId
Why this is wrong:
The Iron Rule: Mock the COMPLETE data structure as it exists in reality, not just fields your immediate test uses.
The fix:
typescript// ✅ GOOD: Mirror real API completeness const mockResponse = { status: 'success', data: { userId: '123', name: 'Alice' }, metadata: { requestId: 'req-789', timestamp: 1234567890 }, // All fields real API returns };
BEFORE creating mock responses:
Check: "What fields does the real API response contain?"
Actions:
1. Examine actual API response from docs/examples
2. Include ALL fields system might consume downstream
3. Verify mock matches real response schema completely
Critical:
If you're creating a mock, you must understand the ENTIRE structure
Partial mocks fail silently when code depends on omitted fields
If uncertain: Include all documented fieldsThe violation:
✅ Implementation complete
❌ No tests written
"Ready for testing"Why this is wrong:
The fix:
TDD cycle:
1. Write failing test
2. Implement to pass
3. Refactor
4. THEN claim completeWarning signs:
your human partner's question: "Do we need to be using a mock here?"
Consider: Integration tests with real components often simpler than complex mocks
Why TDD helps:
If you're testing mock behavior, you violated TDD - you added mocks without watching test fail against real code first.
| Anti-Pattern | Fix | | ------------------------------- | --------------------------------------------- | | Assert on mock elements | Test real component or unmock it | | Test-only methods in production | Move to test utilities | | Mock without understanding | Understand dependencies first, mock minimally | | Incomplete mocks | Mirror real API completely | | Tests as afterthought | TDD - tests first | | Over-complex mocks | Consider integration tests |
*-mock test IDsMocks are tools to isolate, not things to test.
If TDD reveals you're testing mock behavior, you've gone wrong.
Fix: Test real behavior or question why you're mocking at all.
Other measured skills in the registry, with their headline benchmark lift.