如何在Jasmine中模拟Repository触发代码块中的THEN回调?
解决Jasmine测试中无法触发Promise回调的问题
当前模拟代码的问题
- 误用原生
Promise:Angular项目依赖$q实现Promise,原生Promise无法被Angular的digest循环触发,导致then回调不执行 all()方法返回结构错误:你的all()内部then的语法完全错误,正确逻辑是all()返回带有then方法的Promise对象- Spy目标错误:
repo2.states是函数,repo2.states().all才是实际调用的方法,直接监听repo2.states.all无效
正确的模拟实现方式
步骤1:用$q构建符合Angular规范的Mock Repository
在测试中注入$q和$rootScope,用$q.defer()创建可被触发的Promise:
function GetMockFacRepo($q) { return { states: function () { return { all: function () { // 创建deferred对象,定义成功返回的数据 var deferred = $q.defer(); deferred.resolve({ id: 1, name: "测试状态" }); // 可自定义返回的data结构 return deferred.promise; } } } }; }
步骤2:编写完整测试用例
注入Mock的$repository,调用fetchStates()后需手动触发Angular的digest循环,才能执行then回调:
describe('控制器测试', function() { var $controller, $rootScope, $q, mockRepo; var vm; beforeEach(module('你的模块名')); // 替换为实际的Angular模块名称 beforeEach(inject(function(_$controller_, _$rootScope_, _$q_) { $controller = _$controller_; $rootScope = _$rootScope_; $q = _$q_; // 创建Mock Repository实例 mockRepo = GetMockFacRepo($q); // 初始化控制器,注入mock的$repository vm = {}; $controller('你的控制器名', { $repository: mockRepo, vm: vm // 根据控制器实际依赖调整注入项 }); })); it('调用fetchStates后应正确设置vm.states', function() { // 执行目标方法 vm.fetchStates(); // 触发digest循环,触发Promise的then回调执行 $rootScope.$digest(); // 断言vm.states被正确赋值 expect(vm.states).toEqual({ id: 1, name: "测试状态" }); }); });
关键注意点
- 必须使用
$q而非原生Promise:Angular的Promise依赖digest循环解析,原生Promise无法触发该机制 - 手动调用
$rootScope.$digest():执行fetchStates()后,需触发digest才能让then内的代码执行 - 保证Mock层级正确:确保
$repository.states().all()返回的是$q生成的promise对象
内容的提问来源于stack exchange,提问作者David.S.Johnson
相关产品推荐
相关产品推荐

