测试包含.catch()方法的Promise时出错

时间:2016-11-09 02:01:20

标签: angularjs jasmine promise mocha

我有一个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(),则测试通过。

1 个答案:

答案 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(...);

根据经验,最好在测试控制器单元时完全模拟服务,而不仅仅是模拟单个方法。