我有一个Angular1 Controller,它调用一个返回promise的Service。向控制器添加.catch()
方法调用服务时,mocha会抛出以下错误。
TypeError: undefined is not an object (evaluating 'DogService.getDogs(_this.userId)
.then(function(result){
_this.myDogs = result;
})
.catch') in app/scripts/controllers/main.js (line 20)
init@app/scripts/controllers/main.js:20:11
test/spec/controllers/main.js:33:20
loaded@http://localhost:8080/context.js:151:17
控制器
angular.module('testProblemApp').controller('MainCtrl', ['DogService', function (DogService) {
var _this = this;
_this.myDogs = [];
_this.userId = 1;
_this.init = function(){
DogService.getDogs(_this.userId)
.then(function(result){
_this.myDogs = result;
})
.catch(function(error){
console.log(error);
});
};
}]);
测试
describe('initialze function', function () {
it('should set the myDogs array to the value returned by the Service', function () {
spyOn(DogService, 'getDogs').and.callFake(function () {
return {
then: function (callback) {
return callback([{ id: 1, name: 'baxter' }]);
},
catch: function(callback){
return callback('Error');
}
}
});
MainCtrl.init();
expect(MainCtrl.myDogs).toEqual([{ id: 1, name: 'baxter' }]);
});
});
如果我从控制器中删除.catch()
,则测试通过。
答案 0 :(得分:1)
这里的问题是链接。预计then
将返回具有catch
方法的promise对象。 then
模拟中的getDogs
返回undefined
。
使用从头开始编写的自定义存根来模拟承诺或其他核心功能是不方便的。可以使用$q
承诺来测试$q
承诺:
var dogsPromiseMock;
...
spyOn(DogService, 'getDogs').and.callFake(function () {
return dogsPromiseMock;
});
...
dogsPromiseMock = $q.resolve([{ id: 1, name: 'baxter' }]);
MainCtrl.init();
$rootScope.$digest();
expect(MainCtrl.myDogs).toEqual(...);
...
dogsPromiseMock = $q.reject();
MainCtrl.init();
$rootScope.$digest();
expect(MainCtrl.myDogs).toEqual(...);
根据经验,最好在测试控制器单元时完全模拟服务,而不仅仅是模拟单个方法。