Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.
TestingMedium

Follow mocking best practices

Use mocks strategically to isolate units under test without over-mocking.

Utilities
Quick take
Typical fix time 20 min
  • Mock external dependencies (APIs, databases, file system), not business logic
  • Always clean up mocks with jest.restoreAllMocks() in afterEach
  • Use MSW for realistic API mocking without coupling to implementation
  • Test behavior and outputs, not internal implementation details
Why it matters: Proper mocking isolates units under test while keeping tests realistic—over-mocking creates false confidence when tests pass but production breaks.

Rule Details

Effective mocking isolates the code under test while maintaining realistic test scenarios. Over-mocking leads to brittle tests that pass when they should fail.

Code Examples

Module Mocking

// Mock entire module
jest.mock('./api', () => ({
  fetchUser: jest.fn().mockResolvedValue({ id: 1, name: 'Test' })
}))
 
// Mock specific exports
jest.mock('./utils', () => ({
  ...jest.requireActual('./utils'),
  formatDate: jest.fn().mockReturnValue('2024-01-01')
}))

Function Mocking

import { fetchUser } from './api'
 
jest.mock('./api')
const mockFetchUser = fetchUser as jest.MockedFunction<typeof fetchUser>
 
beforeEach(() => {
  mockFetchUser.mockClear()
})
 
test('loads user data', async () => {
  mockFetchUser.mockResolvedValueOnce({ id: 1, name: 'John' })
 
  await loadUserProfile(1)
 
  expect(mockFetchUser).toHaveBeenCalledWith(1)
})

Spy on Methods

test('logs errors to console', () => {
  const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
 
  handleError(new Error('Test'))
 
  expect(consoleSpy).toHaveBeenCalledWith(
    expect.stringContaining('Test')
  )
 
  consoleSpy.mockRestore()
})

Why It Matters

Proper mocking isolates units under test while keeping tests realistic—over-mocking creates false confidence when tests pass but production breaks.

When to Mock

MockDo not Mock
External APIsPure functions
Database callsBusiness logic
File systemData transformations
Time/DateSimple utilities
Network requestsReact components (usually)

Common Mistakes

Over-Mocking

// ❌ Bad: Mocking the thing you're testing
jest.mock('./validateEmail')
test('validates email', () => {
  // This tests nothing!
  expect(validateEmail('test@test.com')).toBe(true)
})
 
// ✅ Good: Test the actual implementation
test('validates email format', () => {
  expect(validateEmail('test@test.com')).toBe(true)
  expect(validateEmail('invalid')).toBe(false)
})

Missing Cleanup

// ❌ Bad: Mocks leak between tests
test('first test', () => {
  jest.spyOn(Date, 'now').mockReturnValue(1000)
  // Forgot to restore!
})
 
test('second test', () => {
  // Date.now is still mocked!
})
 
// ✅ Good: Always cleanup
afterEach(() => {
  jest.restoreAllMocks()
})

Implementation Details

// ❌ Bad: Testing implementation
test('calls internal method', () => {
  const spy = jest.spyOn(component, '_privateMethod')
  component.doSomething()
  expect(spy).toHaveBeenCalled()
})
 
// ✅ Good: Testing behavior
test('updates UI when action completes', () => {
  component.doSomething()
  expect(screen.getByText('Success')).toBeInTheDocument()
})

MSW for API Mocking

import { setupServer } from 'msw/node'
import { rest } from 'msw'
 
const server = setupServer(
  rest.get('/api/user/:id', (req, res, ctx) => {
    return res(ctx.json({ id: req.params.id, name: 'Test User' }))
  })
)
 
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
 
test('fetches user data', async () => {
  render(<UserProfile userId="1" />)
 
  await screen.findByText('Test User')
})

Standards

  • Use these references as the standard for how the test or monitoring strategy should behave in the shipped workflow.
  • Check the implementation against Playwright Docs before treating the rule as satisfied.
  • Check the implementation against Testing Library Guiding Principles before treating the rule as satisfied.

Verification

  1. Run the relevant test or CI step locally and confirm it fails when the rule is violated.
  2. Ensure the automation blocks regressions instead of only printing warnings.
  3. Cover at least one representative high-risk flow, component, or route.
  4. Keep thresholds or assertions in version control so changes remain reviewable.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Review this test file for mocking patterns, checking for over-mocking, missing mock cleanup, and proper mock implementation.

Fix

Auto-fix issues

Improve mocking strategy by removing unnecessary mocks, adding proper cleanup, and mocking at the right level of abstraction.

Explain

Learn more

Explain mocking best practices including when to mock, what to mock, and common mocking pitfalls.

Review

Code review

Review tests, CI workflows, and enforcement points related to Follow mocking best practices. Flag exact gaps where the rule is not automatically verified or where failures do not block regressions.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Playwright
playwright.devTool

Rules that often go hand-in-hand with this one.

Write unit tests

Critical functionality has unit tests with good coverage for reliability.

Testing
Maintain test coverage thresholds

Set and enforce minimum code coverage thresholds to ensure adequate test coverage.

Testing
Write integration tests for key workflows

Test how multiple units of code work together — API routes with their database queries, form submissions with validation, and component trees with their state management.

Testing
Use mutation testing to measure how well tests detect bugs

Run Stryker mutation testing on critical business logic to verify that your test suite will actually catch real bugs, not just achieve line coverage.

Testing

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385