如何在JEST中不使用mock,通过async/await测试React Hooks的异步API调用
问题根源梳理
- 你测试时
booths始终为空的核心原因有两个:
- 原Hook中的
fetchBooths方法没有返回Promise,你用await等待时无法感知到异步请求结束,断言执行时接口还未拿到返回结果,状态还停留在初始值 - 之前的测试代码直接mock了
fetchBooths方法,完全替换了原有逻辑,不会触发真实API调用和全局状态的dispatch
第一步:先修改原Hook的useFetchBooths
给fetchBooths加上return,返回请求的Promise实例,方便测试时等待异步完成:
// 省略其他未改动的代码 function fetchBooths(){ setIsLoading(true) // 新增return返回请求Promise return request.get('/event/get-booth-list') .then((res) => { setIsLoading(false) if (res) { dispatch({ type: SET_BOOTHS, payload: res.data.booth_data }) } return res }) }
第二步:真实API调用测试用例
测试前请确保测试环境可正常访问后端接口,若接口需要鉴权,可在beforeAll钩子中提前完成身份初始化、设置请求头token等操作:
import { renderHook, act } from '@testing-library/react-hooks'; import useFetchBooths from "../../../utils/hooks/useFetchBooths"; import { Store } from "../../../utils/store/context/store"; describe("hook: useFetchBooths", () => { // 测试真实API拉取展位数据 test('真实接口调用成功,booths数据正常更新', async () => { const wrapper = ({ children }) => <Store>{children}</Store> const { result } = renderHook(() => useFetchBooths(), { wrapper }); // 调用拉取方法,等待请求完全结束 await act(async () => { await result.current.fetchBooths(); }); // 校验加载状态结束 expect(result.current.isLoading).toBe(false); // 校验booths已填充了真实数据,不为空 expect(result.current.booths.length).toBeGreaterThan(0); }); // 测试searchBooths功能 test('searchBooths按关键词正确过滤展位', async () => { const wrapper = ({ children }) => <Store>{children}</Store> const { result } = renderHook(() => useFetchBooths(), { wrapper }); // 先拉取全量展位数据 await act(async () => { await result.current.fetchBooths(); }); const originalTotal = result.current.booths.length; expect(originalTotal).toBeGreaterThan(0); // 取第一个展位名称作为搜索关键词,保证匹配结果存在 const validSearchKey = result.current.booths[0].booth_name; act(() => { result.current.searchBooths(validSearchKey); }); // 校验过滤结果全部匹配关键词 result.current.booths.forEach(booth => { expect(booth.booth_name.toLowerCase()).toContain(validSearchKey.toLowerCase()); }); // 测试空关键词重新拉取全量数据 await act(async () => { result.current.searchBooths(''); }); expect(result.current.booths.length).toBe(originalTotal); // 测试不存在的关键词重新拉取全量数据 await act(async () => { result.current.searchBooths('不存在的展位名称123456'); }); expect(result.current.booths.length).toBe(originalTotal); }); });
注意事项
- 真实API测试属于集成测试范畴,依赖后端服务正常运行、网络可访问,执行速度会比Mock接口的单元测试慢
- 如果测试环境存在跨域限制,需要在测试配置中开启代理或者修改接口请求域名的跨域配置,保证
request.get可正常请求到数据
内容的提问来源于stack exchange,提问作者Arslaan Muhammad Ali
相关产品推荐
相关产品推荐

