AngularJS,间谍和解决承诺

时间:2014-07-30 23:30:55

标签: angularjs jasmine

我正在为控制器编写测试。一种方法调用服务中的方法,该方法使用promise。在我的测试中,我嘲笑了服务,并且(我认为)正确地嘲笑了这个承诺。我一直在关注此博客文章:http://codingsmackdown.tv/blog/2012/12/28/mocking-promises-in-unit-tests/

这是测试代码:

describe('Controller: ResultsController', function () {
    'use strict';
    var ctrl;
    var ResultsServiceMock;
    var RouteServiceMock;
    var $scope;
    var mockResults;
    var mockPromise;
    var q;
    var deferred;

    beforeEach(module('waApp'));

    beforeEach(function() {
        ResultsServiceMock = {
            get: function(query) {
                deferred = q.defer();
                return deferred.promise;
            }
        };
        RouteServiceMock = {
            getParams: function() {
            }
        };
    });

    beforeEach(inject(function(
        $rootScope,
        $controller,
        $q
    ) {
        $scope =  $rootScope.$new();
        q = $q;
        ctrl = $controller('ResultsController', {
            $scope: $scope,
            results: ResultsServiceMock,
            route: RouteServiceMock
        });
    }));

    it('Should simulate requesting results from the api', function() {
        spyOn(ResultsServiceMock, 'get').andCallThrough();
        spyOn(RouteServiceMock, 'getParams').andReturn({input:'hamburger'});
        $scope.getResults({input:'hamburger'});  // TODO give params.  try query()
        deferred.resolve();
        $scope.$root.$digest();
        expect($scope.getResults).toHaveBeenCalled();
    });
});

但是,当我运行测试时,我收到以下错误:

Chrome 35.0 (Mac) Controller: ResultsController Should simulate requesting results from the api FAILED

TypeError: Cannot read property 'resolve' of undefined
    at null.<anonymous> (/Users/maryc/wa/app/results/results-controller_test.js:70:17)

Chrome 35.0 (Mac): Executed 14 of 14 (1 FAILED) (0.313 secs / 0.093 secs)

我不明白这个错误来自哪里;是因为对ResultsServiceMock的间谍调用不起作用?任何帮助将不胜感激。

函数getResults如下:

 $scope.getResults = function(params) {¬
     $scope.$emit('startGetResults');¬
     $scope.loading = true;¬
     $scope.podRequestStatus.init = false;¬
     $scope.podRequestStatus = {¬
         async: {}¬
     };¬

     var didyoumeans;¬
     if(params.didyoumeans) {¬
         didyoumeans = params.didyoumeans;¬
         delete params.didyoumeans;¬
     }¬

     ResultsService.get(params).success(function(result) {¬
         $scope.$emit('getResultsSuccess');¬
         if(!_.isUndefined(didyoumeans)) {¬
             $scope.results.queryresult.didyoumeans = didyoumeans;¬
         } else if(!_.isUndefined(result.queryresult.didyoumeans)) {¬
             if (!_.isArray(result.queryresult.didyoumeans)){¬
                 result.queryresult.didyoumeans = [result.queryresult.didyoumeans];¬
             }¬
             $scope.getResults({input: result.queryresult.didyoumeans[0].val, didyoumeans:    result.queryresul    t.didyoumeans});¬
             return;¬
         }¬

         $scope.loading = false;¬

         $scope.podRequestStatus.init = true;¬

         if(result.queryresult.success === false) {  //TODO is this result.results.queryresult.success??¬
             if(result.queryresult.error !== false) {¬
                 $log.error('Results error', 'code: ' + result.queryresult.error.code, 'msg: ' + result.quer    yresult.error.msg);¬
                 switch (result.queryresult.error.code){¬
                     case '3000':¬
                         $location.url('/blockedip');¬
                         break;¬
                 }¬

                 return;¬
             }¬ 

             if($scope.results.queryresult.examplepage && $scope.results.queryresult.examplepage.category) {    ¬
                 $scope.examples();¬
             }¬
             // convert tips to an array if we have a single item¬
             if($scope.results.queryresult.tips && !_.isArray($scope.results.queryresult.tips)){¬
                 $scope.results.queryresult.tips = [$scope.results.queryresult.tips];¬
             }¬
             $log.error('Results error');¬
             return;¬
         }¬

         $scope.results.queryresult.pods = _.map($scope.results.queryresult.pods, function(pod) {¬
             pod.priority = PodService.priority.initial;¬
             return pod;¬
         });¬

         if ($scope.results.queryresult.sources && _.where($scope.results.queryresult.sources, {'text':'Fina    ncial data'})) {¬
             $scope.$emit('financialData', true);¬
         } else {¬
             $scope.$emit('financialData', false);¬
         }¬ ¬

         $scope.asyncPods(PodService.priority.async, 'async');¬
         $scope.recalculate();¬
         $scope.related();¬

     }).error(function() {¬
         $log.error('error occurred during ResultsService.get call in ResultsController');¬                 
     });¬
 };¬

函数asyncPods,recalculate和related是ResultsController中的其他三个方法。

编辑:修复了第一个错误后,我现在在运行测试时遇到以下错误:

Chrome 35.0 (Mac) Controller: ResultsController Should simulate requesting results from the api FAILED
TypeError: undefined is not a function
    at Scope.$scope.getResults (/Users/maryc/wa/.tmp_test/results-controller.js:222:36)
    at null.<anonymous> (/Users/maryc/wa/app/results/results-controller_test.js:67:16)

此错误来自getResults()开头的行,该行调用ResultsService.get()。这似乎暗示我的承诺要么没有得到解决,要么调用$ scope.getResults()以某种方式失败?

ResultsService的.get()函数的代码是:

      get: function(query) {¬
          this.reset();¬
          return ApiService.get({¬
              params: UtilService.merge(query, {¬
                  async: true,¬
                  scantimeout: 1,¬
                  formattimeout: 8,¬
                  parsetimeout: 5,¬
                  format: 'image,plaintext,imagemap',¬
                  banners: 'true'¬
              }),¬
              timeout: abort.promise,¬
              type: 'init',¬
              cache: UserService.user.cacheResults¬
          }).success(function(data){results.queryresult = data.queryresult;});¬                              
      },¬

我现在想知道问题是否.get本身包含一个承诺?

1 个答案:

答案 0 :(得分:0)

根据您目前所包含的信息,我猜测可能导致问题的原因。

$scope.getResults()方法中,您调用了get()的{​​{1}}方法,因此该服务的名称似乎是ResultsService

但在单元测试中,您将ResultsService作为ResultsServiceMock传递:

results

它应该是ctrl = $controller('ResultsController', { $scope: $scope, results: ResultsServiceMock, route: RouteServiceMock }); 而不是这样:

ResultsService

在此更改之后,您可能会遇到其他问题,但它应该会传递错误:

ctrl = $controller('ResultsController', {
  $scope: $scope,
  ResultsService: ResultsServiceMock,
  RouteService: RouteServiceMock
});

希望这有帮助。