React Native中如何用Jest优雅Mock同页面多Axios请求?
解决React Native中Jest多Axios请求Mock维护问题的方案
1. 按请求特征匹配Mock(而非顺序)
直接抛弃按调用顺序返回Mock值的方式,改为根据请求的URL、参数、方法来匹配对应的返回值,从根源避免顺序错误问题。
示例代码:
// 先Mock axios jest.mock('axios'); test('处理多个Axios请求', async () => { // 给不同请求设置对应Mock返回 axios.get.mockImplementation((url) => { if (url === '/api/user') { return Promise.resolve({ data: { id: 1, name: 'Test User' } }); } else if (url === '/api/posts') { return Promise.resolve({ data: [{ id: 1, title: 'Mock Post' }] }); } return Promise.reject(new Error('Unknown URL')); }); // 执行页面逻辑(假设这两个请求调用顺序可能变化) await fetchUser(); await fetchPosts(); // 验证请求是否正确触发 expect(axios.get).toHaveBeenCalledWith('/api/user'); expect(axios.get).toHaveBeenCalledWith('/api/posts'); });
如果需要匹配带参数的请求,可以进一步判断请求配置:
axios.post.mockImplementation((url, data) => { if (url === '/api/login' && data.username === 'test') { return Promise.resolve({ data: { token: 'mock-token' } }); } return Promise.reject(new Error('Invalid credentials')); });
2. 使用Jest的mockReturnValueOnce结合请求标识
如果必须依赖调用顺序,但又想降低维护成本,可以给每个请求添加唯一标识(比如在请求headers里加X-Request-Id),然后在Mock里根据标识判断返回值,同时配合mockReturnValueOnce做兜底,但更推荐第一种方法。
示例代码:
jest.mock('axios'); test('带标识的多请求Mock', async () => { // 按标识映射返回值 const responseMap = new Map([ ['user-fetch', { data: { id: 1 } }], ['posts-fetch', { data: [] }], ]); axios.get.mockImplementation((url, config) => { const requestId = config.headers['X-Request-Id']; return Promise.resolve(responseMap.get(requestId)); }); // 页面请求时携带标识 await axios.get('/api/user', { headers: { 'X-Request-Id': 'user-fetch' } }); await axios.get('/api/posts', { headers: { 'X-Request-Id': 'posts-fetch' } }); });
3. 封装自定义Mock工具类
把Axios的Mock逻辑封装成可复用的工具,统一管理所有请求的Mock规则,避免每个测试文件重复写判断逻辑。
示例工具类:
// __mocks__/axios.js const axios = jest.createMockFromModule('axios'); const mockResponses = new Map(); // 添加Mock规则的方法 axios.mockResponse = (method, url, response) => { mockResponses.set(`${method}-${url}`, response); }; axios.get = jest.fn((url) => { const key = `get-${url}`; return mockResponses.has(key) ? Promise.resolve(mockResponses.get(key)) : Promise.reject(new Error('No mock response set')); }); // 其他方法同理封装post、put等 axios.post = jest.fn((url) => { const key = `post-${url}`; return mockResponses.has(key) ? Promise.resolve(mockResponses.get(key)) : Promise.reject(new Error('No mock response set')); }); // 重置Mock规则的方法 axios.resetMocks = () => { mockResponses.clear(); axios.get.mockClear(); axios.post.mockClear(); }; module.exports = axios;
在测试中使用:
const axios = require('axios'); test('使用自定义Mock工具', async () => { // 设置Mock规则 axios.mockResponse('get', '/api/user', { data: { id: 1 } }); axios.mockResponse('get', '/api/posts', { data: [] }); // 执行请求 await fetchUser(); await fetchPosts(); // 验证 expect(axios.get).toHaveBeenCalledTimes(2); // 测试结束重置Mock axios.resetMocks(); });
4. 替代MSW的轻量方案:Mock Service Worker的React Native适配
MSW本身其实可以在React Native中使用,只是需要额外配置:
- 安装
msw和@mswjs/interceptors - 替换Axios的适配器为MSW的拦截器,或者直接拦截全局的fetch请求(如果项目用fetch的话)
- 注意:React Native中无法使用MSW的浏览器端worker,只能用拦截器模式
示例配置:
// setupTests.js import { setupServer } from 'msw/node'; import { http, HttpResponse } from 'msw'; const server = setupServer( http.get('/api/user', () => { return HttpResponse.json({ id: 1, name: 'Test User' }); }), http.get('/api/posts', () => { return HttpResponse.json([{ id: 1, title: 'Mock Post' }]); }), ); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close());
然后在测试中直接使用Axios发起请求,MSW会自动拦截并返回Mock值,无需手动Mock Axios,这种方式和Web端体验一致,完全解决顺序问题。
内容的提问来源于stack exchange,提问作者komal harmale
相关产品推荐
相关产品推荐

