AngularJS中的控制器中的单元测试承诺

时间:2014-04-10 11:29:44

标签: javascript angularjs unit-testing jasmine

我们最近开始在我们的控制器中加入promises以同时处理多个请求,并且它可以在应用程序中运行,但是单元测试这些已被证明是非常困难的,我将很难抓住它的确切内容我很想念以下是两个片段,它们非常简化我正在尝试测试的内容。

控制器:

angular.module('testengine').controller('testController', [
  '$scope', 
  '$q', 
  'Api', 
  function($scope, $q, Api) {
    $scope.getTest = function (deferred) {

      // do stuff...

      Api.test.get(params, function(response) {
        // do stuff with response

        if (deferred) {
          deferred.resolve(); // if success
        }
      });

    };

    $scope.runTest = function () {

       // do stuff...

       var promises = [];
       var deferred = $q.defer();

       promises.push(deferred.promise);
       $scope.getTest(deferred);

       $q.all(promises).then(function () {
         $scope.navigate();
       }, function () {
         // do stuff with rejected
       });

    };

    $scope.navigate = function () {
      // do stuff
    };
  }]);

测试:

describe('Controller:', function () {

  var root, scope, controllerFactory, $q;

  function createController () {
    return controllerFactory('testController', {
      $scope: scope
    });
  }

  beforeEach(function () {
    module('testengine');
  });

  beforeEach(inject(function ($rootScope, $controller, _$q_) {
    root = $rootScope;
    scope = $rootScope.new();
    controllerFactory = $controller;
    $q = _$q_;
  });

  it('should run test', function () {
    createController();

    var deferred = $q.defer();
    spyOn(scope, 'getTest').andReturn(deferred.resolve());
    spyOn(scope, 'navigate');

    $scope.runTest();

    root.$apply();
    expect(scope.navigate).toHaveBeenCalled();
  });
});

根据所有示例和文档,我已经阅读了promises和$ q,这应该有效,但它没有,而是我得到:

Expected spy navigate to have been called but it was never called.

我猜是因为它与我在嘲笑的间谍中解决的延迟对象不一样,但我怎么想嘲笑那个?我是否必须在控制器或范围上绑定延迟对象或什么?

您看到的结构的原因是因为使用getTest()有不同的方法(有些不仅使用该请求而且还使用其他请求,因此承诺)。此外,getTest()在另一个测试中单独测试,这就是为什么我想要模拟该函数及其中的任何请求。

任何帮助都表示赞赏,如果我犯了一些明显的错误,我很高兴教育自己仍然是Angular的新手。

1 个答案:

答案 0 :(得分:1)

是的,你没有解决正确的承诺。您需要拦截函数参数。

spyOn(scope, 'getTest');
expect(scope.getTest).toHaveBeenCalled();
scope.getTest.mostRecentCall.args[0].resolve();

这是一个很简洁的Jasmine参考:http://tobyho.com/2011/12/15/jasmine-spy-cheatsheet/