Best Patterns for Mocking Axios in Unit Tests
Mocking Axios in unit tests is essential for isolating application
logic, preventing unintended network requests, and creating fast,
deterministic test suites. This article covers the industry-standard
patterns for mocking Axios, focusing on the dedicated
axios-mock-adapter library, native test runner mocking
using Jest or Vitest, and network-level interception with Mock Service
Worker (MSW).
1. Using
axios-mock-adapter (Recommended Axios Pattern)
The most reliable and maintainable way to mock Axios specifically is
using the axios-mock-adapter library. It integrates
directly with Axios instances, allowing you to define route-specific
responses, HTTP status codes, and network delays without overriding the
prototype of Axios itself.
Installation
npm install axios-mock-adapter --save-devImplementation Example
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { fetchUserData } from './userService';
describe('fetchUserData', () => {
let mock;
beforeAll(() => {
// Attach the mock adapter to the default axios instance
mock = new MockAdapter(axios);
});
afterEach(() => {
// Reset handlers between tests
mock.reset();
});
afterAll(() => {
// Restore original axios instance
mock.restore();
});
it('returns data when the API call is successful', async () => {
const mockResponse = { id: 1, name: 'Jane Doe' };
mock.onGet('/users/1').reply(200, mockResponse);
const data = await fetchUserData(1);
expect(data).toEqual(mockResponse);
});
it('handles 404 errors appropriately', async () => {
mock.onGet('/users/999').reply(404);
await expect(fetchUserData(999)).rejects.toThrow();
});
});2. Using Jest or Vitest Built-In Mocks
If you prefer not to install third-party packages, you can mock the
Axios module directly using Jest (jest.mock) or Vitest
(vi.mock). This approach replaces Axios methods with mock
functions.
Implementation Example (Jest)
import axios from 'axios';
import { fetchUserData } from './userService';
jest.mock('axios');
describe('fetchUserData with Jest Mocks', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('fetches successfully data from an API', async () => {
const mockUser = { id: 1, name: 'John Doe' };
axios.get.mockResolvedValueOnce({ data: mockUser });
const result = await fetchUserData(1);
expect(axios.get).toHaveBeenCalledWith('/users/1');
expect(result).toEqual(mockUser);
});
it('handles network failure', async () => {
const errorMessage = 'Network Error';
axios.get.mockRejectedValueOnce(new Error(errorMessage));
await expect(fetchUserData(1)).rejects.toThrow(errorMessage);
});
});Note: When using custom Axios instances created with
axios.create(), module-level mocking requires manually
mocking the create method to return an object with mocked
HTTP methods.
3. Mock Service Worker (MSW)
For broader test coverage across different HTTP clients (Axios, Fetch, etc.), Mock Service Worker intercepts requests at the network level rather than replacing JavaScript modules.
Implementation Example
import { setupServer } from 'msw/node';
import { rest } from 'msw';
import { fetchUserData } from './userService';
const server = setupServer(
rest.get('/users/:id', (req, res, ctx) => {
return res(ctx.json({ id: req.params.id, name: 'Alice' }));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
it('fetches user data via network-level mock', async () => {
const data = await fetchUserData(1);
expect(data).toEqual({ id: '1', name: 'Alice' });
});Key Best Practices
- Always Reset Mocks: Clear or reset mocks in an
afterEachhook to avoid test pollution across different test cases. - Test Error Paths: Ensure your test suite verifies
4xx,5xx, and network timeout behaviors, not just200 OKpaths. - Mock Instances Properly: If your application uses
axios.create(), pass that specific instance intoaxios-mock-adapterrather than the default globalaxiosobject.