AngularJS/Jasmine中嵌套Promise的单元测试实现求助
针对嵌套Promise函数的AngularJS/Jasmine单元测试方案
没问题,我来帮你搞定这个嵌套Promise函数的单元测试。咱们先理清楚functionToTest的核心逻辑:它会先检查是否有未保存变更,再根据用户的确认操作,走两条不同的Promise链。接下来我会分步骤展示如何mock依赖、编写测试用例,覆盖所有关键场景。
第一步:准备测试环境与Mock依赖
首先要mock掉函数里的依赖——customService和hasUnsavedChanges函数,同时注入AngularJS测试必备的$q和$rootScope(因为AngularJS的Promise依赖digest循环才能resolve)。
describe('functionToTest', function() { var customService; var $q; var $rootScope; // 模拟hasUnsavedChanges检查函数 var hasUnsavedChanges; beforeEach(module('yourAppModuleName')); // 替换成你的实际模块名 beforeEach(inject(function(_$q_, _$rootScope_) { $q = _$q_; $rootScope = _$rootScope_; // Mock customService的所有用到的方法 customService = jasmine.createSpyObj('customService', [ 'confirm', 'openSomething', 'doneSomething', 'doSomething', 'doSomethingBeforeDone' ]); // 让每个mock方法默认返回resolved状态的Promise customService.confirm.and.returnValue($q.resolve(true)); customService.openSomething.and.returnValue($q.resolve('mockData')); customService.doneSomething.and.returnValue($q.resolve()); customService.doSomething.and.returnValue($q.resolve()); customService.doSomethingBeforeDone.and.returnValue($q.resolve()); // 模拟hasUnsavedChanges函数 hasUnsavedChanges = jasmine.createSpy('hasUnsavedChanges').and.returnValue(false); })); // 测试用例会写在这里 });
第二步:编写测试用例,覆盖所有场景
场景1:没有未保存变更,函数直接返回
当hasUnsavedChanges()返回false时,函数不会进入任何Promise逻辑,我们要验证这一点:
it('should do nothing when there are no unsaved changes', function() { // 给定:没有未保存变更 hasUnsavedChanges.and.returnValue(false); // 执行函数 var result = functionToTest(); // 断言:customService的所有方法都没被调用 expect(customService.confirm).not.toHaveBeenCalled(); expect(result).toBeUndefined(); // 函数没有返回Promise,结果为undefined });
场景2:有未保存变更,用户确认操作
当hasUnsavedChanges()返回true,且用户点击确认(confirm()返回true),要验证流程走openSomething → doneSomething的链:
it('should execute openSomething -> doneSomething when user confirms', function(done) { // 给定:有未保存变更,且用户确认 hasUnsavedChanges.and.returnValue(true); customService.confirm.and.returnValue($q.resolve(true)); // 执行函数 var promise = functionToTest(); // 触发digest循环,让Promise resolve $rootScope.$apply(); // 断言Promise执行完成后的逻辑 promise.then(function() { expect(customService.confirm).toHaveBeenCalled(); expect(customService.openSomething).toHaveBeenCalled(); expect(customService.doneSomething).toHaveBeenCalled(); // 验证取消分支的方法完全没被调用 expect(customService.doSomething).not.toHaveBeenCalled(); done(); // 通知Jasmine异步测试完成 }).catch(function(err) { done.fail(err); // 如果Promise失败,标记测试失败 }); });
场景3:有未保存变更,用户取消操作
当hasUnsavedChanges()返回true,但用户取消(confirm()返回false),要验证流程走doSomething → doSomethingBeforeDone的嵌套链:
it('should execute doSomething -> doSomethingBeforeDone when user cancels', function(done) { // 给定:有未保存变更,且用户取消 hasUnsavedChanges.and.returnValue(true); customService.confirm.and.returnValue($q.resolve(false)); // 执行函数 var promise = functionToTest(); // 触发digest循环 $rootScope.$apply(); promise.then(function() { expect(customService.confirm).toHaveBeenCalled(); expect(customService.doSomething).toHaveBeenCalled(); expect(customService.doSomethingBeforeDone).toHaveBeenCalled(); // 验证确认分支的方法完全没被调用 expect(customService.openSomething).not.toHaveBeenCalled(); done(); }).catch(function(err) { done.fail(err); }); });
关键注意事项
- 所有涉及Promise的测试都是异步的,必须用
done回调通知Jasmine测试完成 - 一定要调用
$rootScope.$apply()触发AngularJS的digest循环,否则Promise永远不会resolve - 如果需要测试
data参数的处理逻辑,可以给openSomething的mock返回特定数据 - 如果
functionToTest是控制器里的方法,需要先实例化控制器并注入mock服务
内容的提问来源于stack exchange,提问作者Hrishikesh Sardar
相关产品推荐
相关产品推荐

