如何测试嵌套Promise中api.send函数的第二层调用?
多次调用同个异步方法的Mock配置方案
核心问题说明
你当前的写法存在两个问题:
- 链式调用
and.returnValue会直接覆盖前一次的返回值配置,最终所有调用只会返回最后设置的Promise,无法实现两次调用返回不同结果 - 业务代码是Promise异步链式逻辑,测试默认不会等待异步执行完成就运行断言,会导致第二个
api.send还没触发就结束测试
修正方案
1. 用顺序返回值配置两次调用的返回结果
Jest/Jasmine的Spy提供了and.returnValues方法,传入的参数会按调用顺序依次返回,刚好适配你两次调用需要返回不同结果的场景。
2. 等待异步逻辑执行完成再断言
将测试用例改为async函数,调用完目标方法后清空微任务队列,保证所有Promise回调执行完成再运行断言。
修正后的测试代码示例
describe('itemToForm()', () => { // 每次测试跑完清除所有spy,避免用例之间互相影响 afterEach(() => { jest.restoreAllMocks(); }); it('should call api.send first with ES lang parameter', () => { let item = { id: 1, name: 'test' }; component.component = 'Events'; let resEsp = { data: [ { id: 1, name: 'test1' }, { id: 2, name: 'test2' }, { id: 3, name: 'test3' } ] }; component.item = item; let spy1 = spyOn(api, 'send').and.returnValue(Promise.resolve(resEsp)); component.itemToForm(); expect(spy1).toHaveBeenCalled(); expect(spy1).toHaveBeenCalledTimes(1); expect(spy1).toHaveBeenCalledWith('Events', 'get', { lang: 'ES', filter: { id: 1 } }); }); it('should call api.send twice with correct ES and EN parameters', async () => { component.component = 'Events'; // 第一次调用返回的西语数据 const resEsp = {data: [{ id: 1, name: '测试西语名' }, { id: 2, name: 'test2' }, { id: 3, name: 'test3' }]}; // 第二次调用返回的英语数据 const resEng = {data: [{ id: 1, name: 'Test English Name' }, { id: 2, name: 'test2' }, { id: 3, name: 'test3' }]}; component.item = { id: 1, name: '初始名' }; // 按调用顺序配置返回值,第一次返回resEsp,第二次返回resEng const spySend = spyOn(api, 'send').and.returnValues( Promise.resolve(resEsp), Promise.resolve(resEng) ); // 监听setForm调用,可选,用于验证后续逻辑 const spySetForm = spyOn(component, 'setForm'); component.itemToForm(); // 清空微任务队列,等待所有Promise回调执行完成 await Promise.resolve(); // 校验总共调用2次send expect(spySend).toHaveBeenCalledTimes(2); // 校验第一次调用参数(西语请求) expect(spySend).toHaveBeenNthCalledWith(1, 'Events', 'get', { lang: 'ES', filter: { id: 1 } }); // 校验第二次调用参数(英语请求,id取第一次返回结果的id) expect(spySend).toHaveBeenNthCalledWith(2, 'Events', 'get', { lang: 'EN', filter: { id: 1 } }); // 校验最终setForm被调用,可选 expect(spySetForm).toHaveBeenCalled(); }); });
内容的提问来源于stack exchange,提问作者David Angarita
相关产品推荐
相关产品推荐

