如何测试ES6类内的异步axios调用?解决测试报错问题
让我们一步步拆解你遇到的问题,逐个击破:
1. 业务代码中的核心问题
缺失handleAPIResponse方法
你的getUsers方法里调用了this.handleAPIResponse.call(...),但这个方法在MyClass中完全没有定义。当axios请求成功进入then回调时,这会直接抛出错误,进而触发catch块,这是导致后续报错的根源之一。
Catch块写法错误
原代码的catch块只是返回了errorHandler变量,而不是调用它并传入错误信息。正确的逻辑应该是调用errorHandler(error),否则即使进入错误分支,也不会执行预期的错误处理逻辑,还可能因为返回未执行的函数(或参数传递异常)触发TypeError。
修正后的业务代码:
import axios from 'axios'; export default class MyClass{ constructor(config){ this.config = config; } // 补上缺失的handleAPIResponse方法,根据业务逻辑处理响应并调用对应handler handleAPIResponse(resp, successHandler, errorHandler) { if (resp.data) { successHandler(resp.data); return resp.data; } else { errorHandler(new Error('Invalid response data')); return null; } } async getUsers(url, params, successHandler, errorHandler) { return axios.post(url, params) .then(resp => this.handleAPIResponse.call(this, resp, successHandler, errorHandler)) .catch(error => { errorHandler(error); // 按需决定是否reject promise,确保调用方可以捕获错误 return Promise.reject(error); }); } }
2. 测试代码中的变量名错误
你在测试里创建了instance = new MyClass(...),但调用getUsers时却用了myClass.getUsers——这个变量名拼写错误会导致调用异常,甚至让errorHandler参数无法正确传递,直接触发你看到的报错。
另外可以优化mock返回值,让它和handleAPIResponse的预期匹配。修正后的测试代码:
import MyClass from './mycode.js'; import axios from 'axios'; jest.mock('axios'); let instance; // 提前声明实例变量 beforeEach(() => { instance = new MyClass({ env: 'prod' }); }); afterEach(() => { jest.clearAllMocks(); }); test('should return all users and trigger successHandler', async () => { const successHandler = jest.fn(); const errorHandler = jest.fn(); const mockUserData = ['John Doe', 'Charles']; axios.post.mockImplementationOnce(() => { return Promise.resolve({ data: mockUserData }); }); const response = await instance.getUsers('url', {}, successHandler, errorHandler); expect(response).toEqual(mockUserData); expect(successHandler).toHaveBeenCalledTimes(1); expect(successHandler).toHaveBeenCalledWith(mockUserData); expect(errorHandler).not.toHaveBeenCalled(); }); // 新增错误场景测试,覆盖catch分支 test('should trigger errorHandler when request fails', async () => { const successHandler = jest.fn(); const errorHandler = jest.fn(); const mockError = new Error('Request timeout'); axios.post.mockImplementationOnce(() => { return Promise.reject(mockError); }); await instance.getUsers('url', {}, successHandler, errorHandler); expect(errorHandler).toHaveBeenCalledTimes(1); expect(errorHandler).toHaveBeenCalledWith(mockError); expect(successHandler).not.toHaveBeenCalled(); });
3. 关于__mocks__/axios.js的说明
你的mock文件写法是没问题的,测试中用mockImplementationOnce会临时覆盖默认mock行为,完全可以满足当前测试需求。如果后续需要统一默认返回值,再调整这个文件即可。
为什么会出现errorHandler is not a function?
当handleAPIResponse不存在时,then回调抛出错误进入catch块,原代码只是返回errorHandler变量;再加上测试里的变量名错误,导致errorHandler参数未正确传递,最终触发了这个类型错误。修复上述问题后,报错就会消失。
内容的提问来源于stack exchange,提问作者Vinay Mehta

