测试Redux Toolkit+RTK Query的React组件:如何注入API数据?
在RTK Query组件测试中注入模拟数据的三种方法
方法一:手动构造preloadedState中的RTK Query缓存状态
RTK Query的缓存数据存储在Redux store的api切片下(默认reducerPath为api),你可以直接在preloadedState中构造对应结构的缓存数据,让组件读取到预设的孩子列表。
修改你的测试代码如下:
test('显示选中孩子的名字', () => { renderWithProviders(<Status />, { preloadedState: { kids: { selectedKidId: '0' }, api: { queries: { // 键格式为「endpoint名称(参数哈希值)」,这里endpoint是getKids,参数为undefined,所以键是'getKids(undefined)' 'getKids(undefined)': { status: 'fulfilled', data: [ { id: '0', firstName: 'Mike' }, { id: '1', firstName: 'Jane' } ], fulfilledTimeStamp: Date.now() } }, // 补充api切片的必填基础字段,避免初始化报错 providedTags: {}, mutations: {}, config: {}, subscriptions: {}, invalidatedBy: [], isUninitialized: false, isLoading: false, isSuccess: true, isError: false } } }); expect(screen.getByText(/Active: Mike/i)).toBeInTheDocument(); });
注意:这种方法依赖RTK Query内部的缓存键格式,如果你的查询参数复杂,键值可能会变化,稳定性稍差。
方法二:使用RTK Query工具函数填充缓存数据
利用RTK Query提供的updateQueryData工具函数,直接在测试前给指定endpoint注入数据,无需手动构造复杂的缓存结构。
test('显示选中孩子的名字', () => { // 手动创建带有api切片的store const store = configureStore({ reducer: { kids: kidsReducer, // 你的kids切片reducer api: apiReducer // 你的RTK Query api切片reducer }, preloadedState: { kids: { selectedKidId: '0' } } }); // 给getKids endpoint注入模拟数据,参数为undefined(对应组件中useGetKidsQuery的参数) store.dispatch( api.util.updateQueryData('getKids', undefined, () => [ { id: '0', firstName: 'Mike' }, { id: '1', firstName: 'Jane' } ]) ); // 将预填充好数据的store传入renderWithProviders renderWithProviders(<Status />, { store }); expect(screen.getByText(/Active: Mike/i)).toBeInTheDocument(); });
这种方法更可靠,不需要关心内部缓存结构,直接通过官方API操作缓存。
方法三:使用MSW模拟真实API请求
如果希望测试更贴近真实运行场景,可以用Mock Service Worker(MSW)拦截组件发起的API请求,返回模拟数据,无需操作Redux缓存。
- 安装MSW:
npm install msw --save-dev
- 创建请求处理文件(比如
src/mocks/handlers.js):
import { rest } from 'msw'; export const handlers = [ // 匹配组件中getKids请求的API路径 rest.get('/api/kids', (req, res, ctx) => { return res( ctx.json([ { id: '0', firstName: 'Mike' }, { id: '1', firstName: 'Jane' } ]) ); }) ];
- 修改测试文件:
import { setupServer } from 'msw/node'; import { handlers } from '../mocks/handlers'; // 启动MSW服务 const server = setupServer(...handlers); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); test('显示选中孩子的名字', async () => { renderWithProviders(<Status />, { preloadedState: { kids: { selectedKidId: '0' } } }); // 等待异步请求完成并渲染数据 const nameElement = await screen.findByText(/Active: Mike/i); expect(nameElement).toBeInTheDocument(); });
这种方法适合集成测试,能验证组件发起请求、处理响应的完整流程。
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

