如何使用Jest Mock fetch完成POST请求场景的单元测试?
如何使用Jest对fetch语句进行Mock?
现有登录组件代码如下:
export default function Login() { function LoginUser() { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({ username: username, password: password }), }; fetch('http://localhost:8080/post', requestOptions) .then((response) => { if (response.status === 200) { console.log('succesfull'); } else { throw new Error('Invalid credentials'); } }) .catch((err) => { console.log(err); }); } return ( <Button block size='lg' type='submit' onClick={LoginUser} disabled={!validateForm()} > Login </Button> ); }
我们可以通过全局Mock fetch API、模拟不同请求返回值的方式完成单元测试,具体实现如下:
测试代码实现
首先安装必要依赖(已安装可跳过):React组件测试通常搭配@testing-library/react使用,Jest v28+版本需要额外安装jsdom环境模拟浏览器API。
测试文件完整代码:
import { render, screen, fireEvent } from '@testing-library/react'; import Login from './Login'; // 全局Mock浏览器fetch API global.fetch = jest.fn(); // 每次测试执行前清空fetch的调用记录,避免用例之间互相影响 beforeEach(() => { fetch.mockClear(); }); // 测试场景1:登录请求返回200状态(登录成功) test('登录成功时fetch参数符合预期,打印成功日志', async () => { // 模拟fetch返回200成功状态 fetch.mockResolvedValueOnce({ status: 200, json: () => Promise.resolve({}), }); // Mock console.log验证输出结果 const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); // 渲染登录组件 render(<Login />); // 若组件内username、password为受控字段,可在此处先模拟用户输入账号密码: // fireEvent.change(screen.getByLabelText(/用户名/i), { target: { value: 'testUser' } }) // fireEvent.change(screen.getByLabelText(/密码/i), { target: { value: 'testPwd' } }) // 点击登录按钮触发请求 const loginButton = screen.getByRole('button', { name: /login/i }); fireEvent.click(loginButton); // 验证fetch调用参数是否正确 expect(fetch).toHaveBeenCalledTimes(1); expect(fetch).toHaveBeenCalledWith( 'http://localhost:8080/post', expect.objectContaining({ method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, // 此处可替换为你实际传入的账号密码值 body: JSON.stringify({ username: 'testUser', password: 'testPwd' }) }) ); // 等待fetch异步逻辑执行完成 await new Promise(process.nextTick); // 验证成功日志输出 expect(consoleSpy).toHaveBeenCalledWith('succesfull'); // 恢复console.log原始实现 consoleSpy.mockRestore(); }); // 测试场景2:登录请求返回非200状态(登录失败) test('登录失败时抛出错误,打印错误日志', async () => { // 模拟fetch返回401失败状态 fetch.mockResolvedValueOnce({ status: 401, json: () => Promise.resolve({}), }); const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); render(<Login />); const loginButton = screen.getByRole('button', { name: /login/i }); fireEvent.click(loginButton); await new Promise(process.nextTick); expect(consoleSpy).toHaveBeenCalledWith(new Error('Invalid credentials')); consoleSpy.mockRestore(); });
注意事项
- 如果需要测试按钮禁用逻辑,可直接Mock
validateForm方法的返回值,比如返回false后验证按钮disabled属性为true - Jest v28及以上版本默认没有内置jsdom环境,需要手动安装
jest-environment-jsdom,并在jest配置文件中添加testEnvironment: 'jsdom'配置 - 若fetch返回值需要用到
response.json()等其他方法,在mock返回值时补充对应方法即可
内容的提问来源于stack exchange,提问作者bindu shree
相关产品推荐
相关产品推荐

