AngularJS:用$httpBackend测试多请求异步函数遇请求阻塞问题
问题排查与解决方案
核心问题分析
你的测试卡住是因为AngularJS的$http基于$q Promise,而async/await使用原生Promise,两者的调度逻辑不兼容,再加上$httpBackend.flush()的时机错误,导致POST请求处理后,后续的GET请求逻辑没有被触发。具体来说:
- 调用
ctrlInstance.getFormula()后直接flush,只会处理POST请求,但await $http.post(...)后的代码(获取jobId、发起GET请求)会进入原生微任务队列,此时Angular不会自动处理这些微任务,导致GET请求未被发送到$httpBackend。 - 原生Promise的回调不会触发Angular的digest循环,
$qPromise的resolve需要digest才能完成后续逻辑。
修正后的测试代码
使用async/await替代done,分两次flush并协调微任务与digest循环:
it('gets formula from service', async function () { ctrlInstance.searchQuery = 'query'; const jobIDResponse = { job_id: 'dummyJobID', }; const jobResultResponse = { results: [ { result: { formula: 'formula', }, }, ], }; // 匹配所有POST/GET请求 $httpBackend.whenPOST(/.*/).respond(jobIDResponse); $httpBackend.whenGET(/.*/).respond(jobResultResponse); // 启动异步函数,此时POST请求已进入队列 const getFormulaPromise = ctrlInstance.getFormula(); // 第一次flush:处理POST请求,触发digest让$http.post的Promise resolve $httpBackend.flush(); // 等待原生微任务执行:此时async函数会继续执行,发起GET请求 await Promise.resolve(); // 第二次flush:处理GET请求,触发digest让$http.get的Promise resolve $httpBackend.flush(); // 最后触发digest,确保所有$q Promise完成,getFormula的Promise resolve $rootScope.$digest(); // 执行断言 expect(ctrlInstance.improvedFormula).toEqual('formula'); });
关键步骤说明
- 分两次
flush:第一次处理POST请求,让await $http.post()完成;第二次处理GET请求,让await $http.get()完成。 - 等待微任务执行:用
await Promise.resolve()等待原生微任务队列处理,确保发起GET请求的逻辑被执行。 - 触发digest循环:
$httpBackend.flush()会触发一次digest,但最后额外调用$rootScope.$digest()确保所有$qPromise的回调都被执行,让getFormula()的Promise最终resolve。
额外检查点
- 确认
getFormula函数中,postprocessing阶段确实将resultFromService赋值给了ctrlInstance.improvedFormula(比如ctrlInstance.improvedFormula = resultFromService;)。 - 确认
getFormulaFromService中的newurl是否正确使用了jobId构造(如果实际代码需要的话),不过你用/.*/匹配所有GET请求,这一步不会影响测试执行。
内容的提问来源于stack exchange,提问作者jquigs62
相关产品推荐
相关产品推荐

