You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RTL测试中Mock多个Fetch调用并传入自定义数据

问题描述

组件中存在两个独立的Fetch调用:

const fetchPopularCuisines = async() => {
    const data = await fetch(URL2)
    const jsonData = await data.json()
    setPopularCuisines(jsonData?.data?.cards[1])
}

const fetchSuggestions = async() =>{
    const data = await fetch(URL1)
    const jsonData = await data.json() 
    setSearchResults(jsonData?.data?.suggestions)
}

使用React Testing Library(RTL)测试组件时,现有测试代码如下:

// POPULAR_CUISINES_DATA是调用fetchPopularCuisines()时API返回的数据

global.fetch = jest.fn(()=>{
    return Promise.resolve({
        json : () => Promise.resolve(POPULAR_CUISINES_DATA)
    })
})

// 测试上述第一个函数[fetchPopularCuisines()]
test('popular cuisines should render after making an API call', async ()=>{

    const searchBar = render(
        <Provider  store={store}>
            <SearchBar />
        </Provider>
    )
    await waitFor(()=>{
        const cuisinesList = searchBar.getAllByTestId('cuisines-list')
        expect(cuisinesList.length).toBe(12)
    } )

})

当前测试第一个Fetch调用运行正常,但测试第二个fetchSuggestions()时,需要传入自定义数据SEARCH_RESULTS_DATA而非POPULAR_CUISINES_DATA,不知如何实现。同时想了解:若存在n个不同的Fetch调用,该如何分别Mock并为每个调用传入自定义数据?

解决方案

针对不同URL返回不同Mock数据

核心思路是让jest.fn()根据传入的URL参数返回对应数据。给mock的fetch函数添加逻辑,判断调用时传入的URL,再返回对应的数据结构即可。

测试fetchSuggestions()的示例代码

// 定义两个测试数据
const POPULAR_CUISINES_DATA = { /* 对应业务数据 */ };
const SEARCH_RESULTS_DATA = { /* 对应业务数据 */ };

// 重置mock的fetch,避免测试间状态污染
beforeEach(() => {
  global.fetch.mockClear();
});

// 测试fetchPopularCuisines
test('popular cuisines should render after making an API call', async ()=>{
    global.fetch.mockImplementation((url) => {
        if (url === URL2) {
            return Promise.resolve({
                json: () => Promise.resolve(POPULAR_CUISINES_DATA)
            });
        }
        // 其他URL可返回默认结构或抛出错误,按需调整
        return Promise.reject(new Error('Unknown URL'));
    });

    render(
        <Provider store={store}>
            <SearchBar />
        </Provider>
    );

    await waitFor(()=>{
        const cuisinesList = getAllByTestId('cuisines-list');
        expect(cuisinesList.length).toBe(12);
    });
});

// 测试fetchSuggestions
test('search suggestions should render after making an API call', async ()=>{
    global.fetch.mockImplementation((url) => {
        if (url === URL1) {
            return Promise.resolve({
                json: () => Promise.resolve(SEARCH_RESULTS_DATA)
            });
        }
        return Promise.reject(new Error('Unknown URL'));
    });

    render(
        <Provider store={store}>
            <SearchBar />
        </Provider>
    );

    // 根据实际渲染的suggestions元素编写断言
    await waitFor(()=>{
        const suggestions = getAllByTestId('search-suggestions');
        expect(suggestions.length).toBe(5); // 示例断言,需按实际业务调整
    });
});

处理n个不同Fetch调用的通用方案

当存在多个不同URL的Fetch调用时,可以维护一个URL-数据映射表,让mock的fetch函数根据映射表返回对应数据,代码更易维护:

// 定义所有测试数据的映射表
const API_MOCK_DATA = {
    [URL1]: SEARCH_RESULTS_DATA,
    [URL2]: POPULAR_CUISINES_DATA,
    [URL3]: ANOTHER_DATA, // 新增URL对应的数据
    // ... 可扩展更多条目
};

// 通用mock fetch实现
global.fetch.mockImplementation((url) => {
    const mockData = API_MOCK_DATA[url];
    if (mockData) {
        return Promise.resolve({
            json: () => Promise.resolve(mockData)
        });
    }
    // 对未定义的URL,可抛出错误或返回空数据,按需调整
    return Promise.reject(new Error(`No mock data for URL: ${url}`));
});

后续新增Fetch调用时,只需在API_MOCK_DATA中添加对应的URL和数据即可,无需修改mock的核心逻辑。

注意事项

  • 每次测试前必须用mockClear()重置fetch的mock,避免不同测试间的状态污染。
  • 如果组件会同时触发多个Fetch请求(比如挂载时并行调用两个接口),可在mock实现中同时处理多个URL的判断,返回对应数据。

内容的提问来源于stack exchange,提问作者JAY PRAKASH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 15:27:40