React Jest服务执行代码覆盖率测试(Mock Axios调用)问题排查
Jest测试React函数的问题与修复
需求
作为React和Jest新手,需要测试loadUsersData函数,验证以下内容:
callback、dispatch、clearMessage、errMessage是否按逻辑执行service.fetchUsers是否被正确调用,且能返回Mock数据- 覆盖所有代码分支以提升覆盖率
待测试代码
export const loadUsersData = ({requId, dataId, callback, dispatch, clearMessage, errMessage, service}) => { const reqObj = {requId, dataId}; dispatch(clearMessage()); service.fetchUsers(reqObj).then((response) => { const accData = response?.data?.accNumbers ? response.data.accNumbers : []; if(accData.length) { return callback(accData); } else { dispatch(errMessage("No data found")); } }).catch((error) => { dispatch(errMessage("Service failed to load data")); return callback(accData); // 注意:这里accData未定义,属于原代码bug }); }
原测试用例的问题
你尝试的测试代码存在几个问题:
- 语法错误:
async()={应为async () => {;调用函数时错误使用loadUsersData = (...),应该直接调用loadUsersData(...) - 异步未等待:
service.fetchUsers是异步操作,测试未等待Promise完成就执行断言,导致断言时机错误 - spyOn使用不当:
service.fetchUsers已经是Jest mock函数,不需要再用jest.spyOn,直接给mock函数设置返回值即可
原测试代码:
it("fetch data", async()={ // 语法错误:async()={ 应为 async () => { const reqObj = {requId:"123", dataId:"ABC"}; const callback = jest.fn(); const dispatch = jest.fn(); const clearMessage = jest.fn(); const errMessage = jest.fn(); const service = {fetchUsers : jest.fn()} loadUsersData = ({requId:"123", dataId:"ABC", callback, dispatch, clearMessage, errMessage, service}); // 错误:不应赋值,直接调用函数 expect(dispatch).toHaveBeenCalled(); expect(service.fetchUsers).toHaveBeenCalledWith(reqObj); });
使用jest.spyOn报错的原因:本地创建的service对象中,fetchUsers已经是mock函数,spyOn需要监听已存在的非mock方法,直接给service.fetchUsers设置mockResolvedValue即可。
修复后的完整测试用例
以下是覆盖所有分支的测试代码,包含三个核心场景:
场景1:Service返回有效数据
it("调用service获取到有效数据时,执行callback", async () => { const reqObj = { requId: "123", dataId: "ABC" }; const mockAccData = ["acc1", "acc2"]; const callback = jest.fn(); const dispatch = jest.fn(); const clearMessage = jest.fn(); const errMessage = jest.fn(); const service = { fetchUsers: jest.fn().mockResolvedValue({ data: { accNumbers: mockAccData } }) }; await loadUsersData({ requId: reqObj.requId, dataId: reqObj.dataId, callback, dispatch, clearMessage, errMessage, service }); // 验证dispatch调用了clearMessage expect(dispatch).toHaveBeenCalledWith(clearMessage()); // 验证service.fetchUsers被传入正确参数 expect(service.fetchUsers).toHaveBeenCalledWith(reqObj); // 验证callback被传入正确数据 expect(callback).toHaveBeenCalledWith(mockAccData); // 验证errMessage未被调用 expect(errMessage).not.toHaveBeenCalled(); });
场景2:Service返回空数据
it("调用service返回空数据时,触发无数据提示", async () => { const reqObj = { requId: "123", dataId: "ABC" }; const callback = jest.fn(); const dispatch = jest.fn(); const clearMessage = jest.fn(); const errMessage = jest.fn(); const service = { fetchUsers: jest.fn().mockResolvedValue({ data: { accNumbers: [] } }) }; await loadUsersData({ requId: reqObj.requId, dataId: reqObj.dataId, callback, dispatch, clearMessage, errMessage, service }); expect(dispatch).toHaveBeenCalledWith(errMessage("No data found")); expect(callback).not.toHaveBeenCalled(); });
场景3:Service请求失败
it("service请求失败时,触发错误提示", async () => { const reqObj = { requId: "123", dataId: "ABC" }; const callback = jest.fn(); const dispatch = jest.fn(); const clearMessage = jest.fn(); const errMessage = jest.fn(); const service = { fetchUsers: jest.fn().mockRejectedValue(new Error("请求失败")) }; await loadUsersData({ requId: reqObj.requId, dataId: reqObj.dataId, callback, dispatch, clearMessage, errMessage, service }); expect(dispatch).toHaveBeenCalledWith(errMessage("Service failed to load data")); // 注意:原代码catch块中使用了未定义的accData,会导致报错,建议修复为callback([])或其他合理逻辑 });
额外注意事项
- 原代码的
catch块中使用了accData变量,但该变量仅在then块中定义,会导致未定义错误,建议修复为callback([])或其他合理逻辑 - 所有异步测试必须使用
await等待Promise完成,否则断言会在异步操作结束前执行,导致结果不符合预期
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

