嵌套调用api.send时第二个Promise未触发,单元测试校验失败如何解决
问题根因
- 方法调用不匹配:业务逻辑定义的方法是
getItemForm,但测试代码中调用的是itemToForm,调用错误是首要问题 - 未等待异步执行:Promise回调属于微任务,会在所有同步代码执行完成后才触发,你当前的测试断言是同步执行的,此时第一个
then回调还没运行,第二次api.send自然还没有被调用 - 测试代码存在语法冗余:
component.item = let item = {...}是无效语法,多余的let item =会导致运行异常
修复方案
1. 优化业务代码(可选但推荐)
给Promise链加上返回,方便外部追踪异步执行状态,避免嵌套Promise回调丢失上下文:
getItemForm = () => { // 返回外层Promise return this.api.send('filter', 'get', { lang: 'ES', filter: { id: this.item['id'] } }).then(res1 => { this.item = res1['data'][0]; // 返回内层Promise,形成完整链式结构 return this.api.send('filter', 'get', { lang: 'EN', filter: { id: this.item['id'] } }).then(res2 => { let itemEng = res2['data'][0]; return itemEng; }); }); };
2. 修正测试代码
用async/await等待异步逻辑全部执行完成后再做断言,同时修正方法调用和语法错误:
// 测试函数添加async关键字支持异步等待 it('should call api.send with res Eng', async () => { component.formDef = [{ field_id: 57, field_key: "name1", field_name: 'test1' }]; let res1 = { data: [{ id: 1, name: 'test1' }, { id: 2, name: 'test1' }] }; let res2 = { data: [{ id: 1, name: 'test2' }, { id: 2, name: 'test' }] }; // 修正语法错误,删掉多余的let item声明 component.item = {id:1, count: 1, data:[{id: 1, tacticas: {95: [135]}}]}; let spy1 = spyOn(api, 'send').and.returnValues(Promise.resolve(res1), Promise.resolve(res2)); // 调用正确的业务方法,等待异步逻辑全部执行完成 await component.getItemForm(); expect(spy1).toHaveBeenCalled(); expect(spy1).toHaveBeenCalledTimes(2); // 可补充参数校验的断言,保证调用逻辑正确 expect(spy1).toHaveBeenNthCalledWith(1, 'filter', 'get', { lang: 'ES', filter: { id: 1 } }); expect(spy1).toHaveBeenNthCalledWith(2, 'filter', 'get', { lang: 'EN', filter: { id: 1 } }); });
如果不想修改业务代码添加Promise返回,也可以在测试中用微任务清空工具(如Jest的flushPromises、Angular测试的flushMicrotasks)配合done回调完成异步等待,效果一致。
内容的提问来源于stack exchange,提问作者David Angarita
相关产品推荐
相关产品推荐

