- Test Quality Analysis
- Expert knowledge for analyzing and improving test quality - detecting test smells, overmocking, insufficient coverage, and testing anti-patterns.
- Core Dimensions
- Correctness
-
- Tests verify the right behavior
- Reliability
-
- Tests are deterministic, not flaky
- Maintainability
-
- Tests are easy to understand
- Performance
-
- Tests run quickly
- Coverage
-
- Tests cover critical code paths
- Isolation
-
- Tests don't depend on external state
- Test Smells
- Overmocking
- Problem
-
- Mocking too many dependencies makes tests fragile.
- // ❌ BAD: Overmocked
- test
- (
- 'calculate total'
- ,
- (
- )
- =>
- {
- const
- mockAdd
- =
- vi
- .
- fn
- (
- (
- )
- =>
- 10
- )
- const
- mockMultiply
- =
- vi
- .
- fn
- (
- (
- )
- =>
- 20
- )
- // Testing implementation, not behavior
- }
- )
- // ✅ GOOD: Mock only external dependencies
- test
- (
- 'calculate order total'
- ,
- (
- )
- =>
- {
- const
- mockPricingAPI
- =
- vi
- .
- fn
- (
- (
- )
- =>
- (
- {
- tax
- :
- 0.1
- }
- )
- )
- const
- total
- =
- calculateTotal
- (
- order
- ,
- mockPricingAPI
- )
- expect
- (
- total
- )
- .
- toBe
- (
- 38
- )
- }
- )
- Detection
-
- More than 3-4 mocks, mocking pure functions, complex mock setup.
- Fix
-
- Mock only I/O boundaries (APIs, databases, filesystem).
- Fragile Tests
- Problem
-
- Tests break with unrelated code changes.
- // ❌ BAD: Tests implementation details
- await
- page
- .
- locator
- (
- '.form-container > div:nth-child(2) > button'
- )
- .
- click
- (
- )
- // ✅ GOOD: Semantic selector
- await
- page
- .
- getByRole
- (
- 'button'
- ,
- {
- name
- :
- 'Submit'
- }
- )
- .
- click
- (
- )
- Flaky Tests
- Problem
- Tests pass or fail non-deterministically. // ❌ BAD: Race condition test ( 'loads data' , async ( ) => { fetchData ( ) await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) expect ( data ) . toBeDefined ( ) } ) // ✅ GOOD: Proper async handling test ( 'loads data' , async ( ) => { const data = await fetchData ( ) expect ( data ) . toBeDefined ( ) } ) Poor Assertions // ❌ BAD: Weak assertion test ( 'returns users' , async ( ) => { const users = await getUsers ( ) expect ( users ) . toBeDefined ( ) // Too vague! } ) // ✅ GOOD: Strong, specific assertions test ( 'creates user with correct attributes' , async ( ) => { const user = await createUser ( { name : 'John' } ) expect ( user ) . toMatchObject ( { id : expect . any ( Number ) , name : 'John' , } ) } ) Analysis Tools
Vitest coverage (prefer bun)
bun test --coverage open coverage/index.html
Check thresholds
bun test --coverage --coverage.thresholds.lines = 80
pytest-cov (Python)
- uv run pytest
- --cov
- --cov-report
- =
- html
- open
- htmlcov/index.html
- Best Practices Checklist
- Unit Test Quality (FIRST)
- Fast
-
- Tests run in milliseconds
- Isolated
-
- No dependencies between tests
- Repeatable
-
- Same results every time
- Self-validating
-
- Clear pass/fail
- Timely
- Written alongside code Mock Guidelines Mock only external dependencies Don't mock business logic or pure functions Use real implementations when possible Limit to 3-4 mocks per test maximum Coverage Goals 80%+ line coverage for business logic 100% for critical paths (auth, payment) All error paths tested Boundary conditions tested Test Structure (AAA Pattern) test ( 'user registration' , async ( ) => { // Arrange const userData = { email : 'user@example.com' } // Act const user = await registerUser ( userData ) // Assert expect ( user . email ) . toBe ( 'user@example.com' ) } ) Code Review Checklist Tests verify behavior, not implementation Assertions are specific and meaningful No flaky tests (timing, ordering issues) Proper async/await usage Test names clearly describe behavior Minimal code duplication Critical paths have tests Both happy path and error cases covered Common Anti-Patterns Testing Implementation Details // ❌ BAD const spy = vi . spyOn ( Math , 'sqrt' ) calculateDistance ( ) expect ( spy ) . toHaveBeenCalled ( ) // Testing how, not what // ✅ GOOD const distance = calculateDistance ( { x : 0 , y : 0 } , { x : 3 , y : 4 } ) expect ( distance ) . toBe ( 5 ) // Testing output Mocking Too Much // ❌ BAD const mockAdd = vi . fn ( ( a , b ) => a + b ) // ✅ GOOD: Use real implementations import { add } from './utils' // Only mock external services const mockPaymentGateway = vi . fn ( ) See Also vitest-testing - TypeScript/JavaScript testing playwright-testing - E2E testing mutation-testing - Validate test effectiveness