【问题标题】:Unit testing promises in controllers in AngularJSAngularJS 控制器中的单元测试承诺
【发布时间】:2014-04-10 11:29:44
【问题描述】:

我们最近开始在我们的控制器中加入 Promise 以同时处理多个请求,并且它在应用程序中工作,但事实证明,对这些进行单元测试非常困难,我很难准确掌握它的含义是我失踪了。以下是我要测试的两个非常简化的 sn-ps。

控制器:

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();
  });
});

根据我在 Promise 和 $q 上阅读的所有示例和文档,这应该有效,但它没有,相反我得到:

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

我猜是因为它不是我在模拟间谍中解析的同一个延迟对象,但我应该如何模拟它?我是否必须在控制器或范围上绑定延迟对象或什么?

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

感谢任何帮助,如果我犯了一些明显的错误,我很乐意教育自己对 Angular 还是很陌生。

【问题讨论】:

  • 我怀疑重构可以做一些事情:看起来有点像Api.test.get 应该返回一个承诺,而不是接受一个回调。 $scope.getTest 也应该返回一个承诺,而不是影响它然后解析的延迟对象。我认为这会使事情变得更加标准,并使他们的测试也最标准和(希望)更简单。诚然很难知道/确定,因为我不确定这些功能都做了什么。阅读链式 Promise 可能会有所帮助(尽管 Angular 文档对此非常简单!)。

标签: javascript angularjs unit-testing jasmine


【解决方案1】:

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

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

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

【讨论】:

  • 这很有意义,而且帮助很大。谢谢!
猜你喜欢
  • 2015-03-15
  • 2016-07-25
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-12
相关资源
最近更新 更多