React单元测试中如何mock异步方法并验证回调入参为更新后的state值
核心问题分析
- 原组件执行顺序错误:
getData是异步方法,then回调属于微任务,会在同步代码执行完成后才触发。原代码中foo(this.state.data)是同步执行的,此时setState还未运行,拿到的永远是data的初始值,和测试逻辑无关。 - 测试代码逻辑缺陷:
jest.mock直接赋值给serviceObj的用法错误,jest.mock是模块级别 mock 声明,不会返回 mock 后的模块实例,需要通过导入获取 mock 后的对象- 未等待异步逻辑执行完成就直接断言,此时异步请求、状态更新的逻辑都未运行
- 未对
foo方法做 mock 配置,无法捕获它的调用参数
修复步骤
1. 修正组件业务逻辑
要让foo在state更新完成后调用,可以把foo放到setState的第二个回调参数中(setState第二个回调会在状态更新、组件重渲染完成后触发):
componentDidMount() { serviceObj.getData().then(response => { this.setState({data: response.data}, () => { // 此时state已经更新完成,拿到的是最新值 foo(this.state.data); }); }); }
2. 修正单元测试用例
需要先完成foo和服务模块的 mock,再用waitFor等待异步逻辑执行完成后再断言:
// 顶部先做模块mock,注意jest.mock要放在模块导入之前 // 假设foo从fooModule导入,根据实际路径修改 jest.mock('path/to/fooModule', () => ({ __esModule: true, default: jest.fn() })); // mock服务模块 jest.mock('serviceModule', () => ({ __esModule: true, default: { getData: jest.fn(() => Promise.resolve({data: "test"})) } })); // 导入依赖 import { render, waitFor } from '@testing-library/react'; import foo from 'path/to/fooModule'; import MyComponent from './MyComponent'; it('调用foo时传入接口返回的最新data值', async () => { render(<MyComponent />); // 等待异步逻辑执行完成,确认foo调用参数符合预期 await waitFor(() => { expect(foo).toHaveBeenCalledWith("test"); }); });
内容的提问来源于stack exchange,提问作者Boon
相关产品推荐
相关产品推荐

