avoiding-testing-anti-patterns
SKILL.md
Avoiding Testing Anti-Patterns
Quick Start
- Identify - Recognize anti-pattern category (flaky, implementation, over-mocking)
- Assess Severity - Critical (fix now), High (fix soon), Medium (plan to fix)
- Apply Fix - Use proper async handling, test behavior not implementation
- Verify - Run tests in random order, ensure independence
- Prevent - Add test smell detection to CI
Features
| Feature | Description | Guide |
|---|---|---|
| Flaky Tests | Random failures destroying trust | Use waitFor, not sleep; deterministic data |
| Implementation Testing | Breaks on every refactor | Test behavior through public interface |
| Over-Mocking | Tests pass but bugs slip through | Mock boundaries only, not your own code |
| Slow Tests | Hurt development velocity | Right test layer, shared setup, mock network |
| Test Interdependence | Can't run tests in isolation | Fresh state in beforeEach, no shared mutation |
| Poor Design | Hard to understand/maintain | Descriptive names, focused tests, clear values |
Common Patterns
// FLAKY: Timing-dependent
await sleep(100); // May not be enough
expect(result).toBe('processed');
// FIXED: Wait for condition
await waitFor(() => {
expect(result).toBe('processed');
}, { timeout: 5000 });
// FLAKY: Shared state between tests
let sharedState = [];
it('test1', () => { sharedState.push('a'); });
it('test2', () => { expect(sharedState).toHaveLength(1); }); // Order-dependent!
// FIXED: Fresh state each test
beforeEach(() => { sharedState = []; });
// IMPLEMENTATION: Testing private state
expect(counter._count).toBe(1);
// BEHAVIOR: Testing public interface
expect(counter.getValue()).toBe(1);
// OVER-MOCKING: Everything mocked
const mockDb = { save: jest.fn() };
const mockPayment = { charge: jest.fn() };
// Only testing that mocks were called
// FIXED: Mock boundaries only
const testDb = await createTestDatabase(); // Real
const mockPayment = createMockPaymentProvider(); // External only
# Anti-Pattern Severity Guide
CRITICAL (fix immediately):
- Flaky tests - Random failures destroy trust
- Testing implementation - Breaks on every refactor
- Hidden dependencies - Tests fail mysteriously
HIGH (fix soon):
- Slow tests - Hurt development velocity
- Test interdependence - Can't run in isolation
- Over-mocking - Tests pass but bugs slip through
MEDIUM (plan to fix):
- Poor naming - Tests don't document behavior
- Magic values - Unclear expected values
- Giant tests - Hard to understand
LOW (fix when touching):
- Commented tests - Remove or fix
- Duplicate tests - Consolidate
Best Practices
| Do | Avoid |
|---|---|
| Test behavior, not implementation | Accessing private properties |
| Use factories for test data | Random/inconsistent test data |
| Write descriptive test names | Generic names like "test1", "should work" |
| Keep tests independent | Shared mutable state between tests |
| Mock only external boundaries | Mocking your own code extensively |
| Use waitFor, not sleep | setTimeout/sleep in tests |
| Make assertions specific | toBeDefined() for everything |
| Run tests in random order | Assuming test execution order |
Related Skills
developing-test-driven- TDD with proper patternstesting-with-vitest- Vitest testing frameworktesting-with-playwright- E2E testing patternsdebugging-systematically- Debug flaky test failures
Weekly Installs
1
Repository
doanchienthangdev/omgkitGitHub Stars
3
First Seen
6 days ago
Security Audits
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1