From claudekit
Identifies and corrects testing anti-patterns like testing mock behavior instead of real code, over-mocking dependencies, and adding test-only methods to production code. Use for writing, reviewing, or debugging tests.
npx claudepluginhub duthaho/claudekit --plugin claudekitThis skill uses the workspace's default tool permissions.
- Writing new tests
Prevents testing anti-patterns like verifying mock behavior, adding test-only methods to production code, and mocking without understanding dependencies. Use when writing, changing tests, or adding mocks.
Guards against testing anti-patterns: testing mock behavior, production test-only methods, and mocking without understanding dependencies. Triggers on test reviews, mock additions, or suspicious passing tests.
Detects test smells like overmocking, flaky tests, fragile tests, poor assertions, and coverage issues. Analyzes test correctness, reliability, maintainability when reviewing or improving tests.
Share bugs, ideas, or general feedback.
The Problem: Tests verify mocks work, not that actual code works.
// BAD: Testing the mock
it('should call the database', () => {
const mockDb = { save: jest.fn().mockResolvedValue({ id: 1 }) };
const service = new UserService(mockDb);
await service.createUser({ name: 'Test' });
expect(mockDb.save).toHaveBeenCalled(); // Only proves mock was called
});
The Solution: Test actual behavior with real (or realistic) dependencies.
// GOOD: Testing real behavior
it('should persist user to database', async () => {
const db = await createTestDatabase();
const service = new UserService(db);
const result = await service.createUser({ name: 'Test' });
const saved = await db.findById(result.id);
expect(saved.name).toBe('Test'); // Proves data was actually saved
});
Key Principle: "Test what the code does, not what the mocks do."
The Problem: Adding methods to production code solely for test cleanup or access.
// BAD: Production class with test-only method
class ConnectionPool {
private connections: Connection[] = [];
// This method exists only for tests
destroy(): void { // DON'T DO THIS
this.connections.forEach(c => c.close());
this.connections = [];
}
}
The Solution: Handle cleanup in test utilities, not production code.
// GOOD: Test utility handles cleanup
// test-utils/connection-pool.ts
export async function withTestPool(fn: (pool: ConnectionPool) => Promise<void>) {
const pool = new ConnectionPool();
try {
await fn(pool);
} finally {
// Cleanup handled by test infrastructure
await closeAllConnections(pool);
}
}
Key Principle: Production code should never know it's being tested.
The Problem: Over-mocking to "be safe" removes behavior the test actually depends on.
// BAD: Mocking everything blindly
it('should process order', () => {
jest.mock('./inventory'); // What does this mock?
jest.mock('./payment'); // Did we need to mock this?
jest.mock('./shipping'); // This might break the test logic
const result = processOrder(order);
expect(result.status).toBe('complete');
});
The Solution: Understand what each dependency does before mocking it.
// GOOD: Selective, understood mocking
it('should process order when payment succeeds', () => {
// Only mock external service (payment gateway)
// Keep inventory and shipping real for integration test
const paymentGateway = createMockPaymentGateway({
chargeResult: { success: true, transactionId: 'txn-123' }
});
const result = processOrder(order, { paymentGateway });
expect(result.status).toBe('complete');
expect(result.transactionId).toBe('txn-123');
});
Key Principle: Mock at boundaries, not internally.
The Problem: Partial mocks that only include known fields, hiding structural assumptions.
// BAD: Incomplete mock
const mockApiResponse = {
data: { users: [] }
// Missing: status, headers, pagination, errors
};
it('should handle API response', () => {
fetchMock.mockResolvedValue(mockApiResponse);
const result = await getUsers();
expect(result).toEqual([]);
});
// Test passes, but production fails when accessing response.pagination
The Solution: Create complete mocks that match real API responses.
// GOOD: Complete mock matching real response structure
const mockApiResponse = {
status: 200,
headers: { 'content-type': 'application/json' },
data: {
users: [],
pagination: { page: 1, total: 0, hasMore: false },
errors: null
}
};
it('should handle empty API response', () => {
fetchMock.mockResolvedValue(mockApiResponse);
const result = await getUsers();
expect(result.users).toEqual([]);
expect(result.hasMore).toBe(false);
});
Key Principle: Mocks should be indistinguishable from real responses.
The Problem: Treating testing as optional follow-up work rather than integral to development.
// BAD: Tests written after code, just verifying what exists
it('should do what the function does', () => {
// This test was written by looking at the implementation
// It tests the current behavior, not the intended behavior
const result = processData(input);
expect(result).toMatchSnapshot(); // "Whatever it does is correct"
});
The Solution: Use TDD - tests define requirements before implementation.
// GOOD: Test written first, defines requirement
it('should filter inactive users from report', () => {
const users = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false }
];
const report = generateReport(users);
expect(report.users).toHaveLength(1);
expect(report.users[0].name).toBe('Alice');
});
// Now implement generateReport to make this pass
Key Principle: TDD prevents all these anti-patterns naturally.
| Symptom | Likely Anti-Pattern |
|---|---|
| Tests pass but bugs ship | #1 Testing mocks |
destroy() or reset() in production | #2 Test pollution |
| "I mocked that to be safe" | #3 Blind mocking |
| TypeError in production, not tests | #4 Incomplete mocks |
| Tests feel like documentation | #5 Afterthought tests |
Before committing tests, verify:
"Mocks are tools to isolate, not things to test."
Mocks help you:
Mocks should never:
test-driven-development -- TDD naturally prevents most testing anti-patterns by requiring tests before implementationpytest -- Python-specific testing best practices that complement anti-pattern awarenessvitest -- TypeScript/JavaScript-specific testing best practices that complement anti-pattern awareness