简体   繁体   English

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

[英]Unit testing promises in controllers in AngularJS

We recently started incorporating promises in our controllers to handle multiple requests at the same time and it works in the app, but unit testing these has been proven to be more than difficult and I will I have a hard time grasping exactly what it is I'm missing. 最近,我们开始将诺言纳入控制器中,以同时处理多个请求,并且在应用程序中可以正常工作,但是事实证明,对这些请求进行单元测试不仅困难,而且我将很难理解确切的含义。我不见了。 Following are two snippets that are very simplified on what I'm exactly trying to test. 以下是两个片段,它们对我要测试的内容进行了非常简化。

Controller: 控制器:

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

Test: 测试:

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

According to all examples and documentation I've read on promises and $q, this should work, but it doesn't, instead I get: 根据我阅读过的promise和$ q的所有示例和文档,这应该可以,但是不能,相反,我得到:

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

I'm guessing because it's not the same deferred object I'm resolving in my mocked spy, but how am I suppose to mock that? 我猜是因为它与我在模拟间谍中解决的延迟对象不同,但是我应该如何模拟呢? Do I have to bind the deferred object on the controller or the scope or what? 我是否必须在控制器或示波器上绑定延迟的对象,或者什么?

The reason for the structure you see is because there are different methods using getTest() (and some do not only use that request but also others, hence promises). 您看到的结构的原因是因为有多种使用getTest()的方法(有些方法不仅使用该请求,而且还使用其他方法,因此是可以保证的)。 Also, getTest() is tested separately in another test, which is why I want to mock that function and any requests made in it. 另外,getTest()在另一个测试中分别进行了测试,这就是为什么我要模拟该函数及其中的任何请求。

Any help is appreciated and if I've made some blatant errors, I'm happy to educate myself being still fairly new to Angular. 感谢您的帮助,如果我犯了一些明显的错误,我很高兴教育自己对Angular还是很陌生。

Yes, you are not resolving the right promise. 是的,您没有兑现正确的承诺。 You need to intercept the function arguments. 您需要拦截函数参数。

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

This is a good concise Jasmine reference: http://tobyho.com/2011/12/15/jasmine-spy-cheatsheet/ 这是一个很好的简洁茉莉花参考: http : //tobyho.com/2011/12/15/jasmine-spy-cheatsheet/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM