React Query + Vitest模拟请求:多测试用例运行冲突问题求助
问题原因与解决方案
核心问题
你遇到的测试污染问题,根源在于 vi.mock的提升特性:Vitest会自动把所有vi.mock调用提升到文件作用域的最顶部执行,而非按测试用例顺序运行。这意味着两个测试里的vi.mock会在所有测试开始前就被处理,后一个mock会直接覆盖前一个的实现,导致测试间逻辑冲突。另外,vi.clearAllMocks()仅清除mock的调用记录(比如调用次数、参数),不会重置mock的返回值实现;同时React Query自带的缓存机制会保留前一个测试的数据,进一步加剧测试污染。
修复方案
1. 统一mock + 动态修改返回值
把vi.mock移到文件顶部只执行一次,然后在每个测试用例里通过vi.mocked()动态设置不同返回值:
// 先导入目标hook,在文件顶部统一mock import useInformationQuery from '../../useInformationQuery'; vi.mock('../../useInformationQuery'); const renderComponent = () => { // 关键:每次渲染都创建新的QueryClient,彻底隔离缓存 const queryClient = new QueryClient(); return render( <QueryClientProvider client={queryClient}> <UserInformationComponent /> </QueryClientProvider> ); }; describe('UserInformationComponent', () => { beforeEach(() => { // 清除mock调用记录 vi.clearAllMocks(); }); it('渲染类型1的数据', async () => { // 动态设置当前测试的mock返回值 vi.mocked(useInformationQuery).mockReturnValue([ { data: /* 类型1的测试数据 */ } ]); renderComponent(); // ...你的断言逻辑 }); it('渲染类型2的数据', async () => { vi.mocked(useInformationQuery).mockReturnValue([ { data: /* 类型2的测试数据 */ } ]); renderComponent(); // ...你的断言逻辑 }); });
2. 处理带参数的hook场景
如果useInformationQuery需要根据传入的type参数返回不同数据,用mockImplementation替代mockReturnValue:
it('根据参数返回对应数据', async () => { vi.mocked(useInformationQuery).mockImplementation((type) => { if (type === 'type1') { return [{ data: /* 类型1数据 */ }]; } else if (type === 'type2') { return [{ data: /* 类型2数据 */ }]; } return [{ data: null }]; }); renderComponent(); // ...断言逻辑 });
3. 彻底隔离React Query缓存
上面的renderComponent每次都创建新的QueryClient是最稳妥的缓存隔离方式。如果用了自定义wrapper,可修改wrapper逻辑确保每个测试用全新的QueryClient:
const createWrapper = () => { // 每次调用createWrapper都生成新的QueryClient const queryClient = new QueryClient(); return ({ children }) => ( <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> ); };
内容的提问来源于stack exchange,提问作者heliosk
相关产品推荐
相关产品推荐

