《棱角分明》和《茉莉花》:如何嘲弄回报承诺的服务

时间:2022-03-12 19:43:16

I have the following controller in AngularJS that is invoking a service provided by "$mdSidenav" from Angular Material. This is service is provided by a factory method.

我在AngularJS中有以下控制器,它正在从角度材料中调用“$mdSidenav”提供的服务。这是由工厂方法提供的服务。

angular.module('leopDirective', [])
    .controller('MenuCtrl', function ($scope,$timeout,$mdSidenav,$log) {

    $scope.mdSidenav = $mdSidenav;
    $scope.close = function () {
        $mdSidenav('left').close().then(function() {$scope.closed=true; });
    };

});

I am trying to mock that service ($mdSidenav) in order to test my controller. The following is the source code of the Jasmine test that I am trying to define:

为了测试我的控制器,我尝试模拟这个服务($mdSidenav)。下面是我正在尝试定义的茉莉花测试的源代码:

describe('Controller: MenuCtrl', function() {
    var $rootScope, $scope, $controller, $q, menuCtrl,
        mock__mdSidenav = function(component) {
            return {
                // THIS FUNCTION IS EMPTY SINCE $Q IS NOT AVAILABLE
                close: function() {}
            }
        };

    beforeEach(function() {
        module('leopDirective', function($provide) {
            // I HAVE TO PROVIDE THE MOCK UP BEFORE INJECTING $Q
            $provide.value('$mdSidenav', mock__mdSidenav);
        });
        inject(function($injector) {
            $rootScope = $injector.get('$rootScope');
            $controller = $injector.get('$controller');
            $q = $injector.get('$q');
            $scope = $rootScope.$new();
        });
        menuCtrl = $controller("MenuCtrl", { $scope: $scope });
    });

    it('should create the $mdSidenav object', function() {
        var deferred = $q.defer(),
            promise = deferred.promise;
        // NOW THAT $Q IS AVAILABLE, I TRY TO FILL UP THE FUNCTION
        mock__mdSidenav.close = function() {
            return promise.then(function(response){return response.success;});
        };
        // force `$digest` to resolve/reject deferreds
        $rootScope.$digest();
        // INVOKE FUNCTION TO TEST
        $scope.close();
    });
});

The problem that I have is that I do not know how to create a function for the mock that returns a promise:

我遇到的问题是,我不知道如何为mock创建返回承诺的函数:

  1. creating a promise depends on $q,
  2. 创造一个承诺取决于$q,
  3. $q has to be injected from within the block "inject",
  4. $q必须从block "inject"中注入,
  5. however, $provide has to be used within "module", just before "inject",
  6. 但是,必须在“模块”中使用$provide,就在“注入”之前,
  7. therefore, the function that returns a promise within my mock object (mock__mdSidenav().close()), has to be empty at the before invoking "$provide" and, somehow, created later on.
  8. 因此,在我的模拟对象中返回一个承诺的函数(mock__mdSidenav().close()),在调用“$提供”之前必须是空的,然后在稍后创建。

With this approach, the error that I am getting is the following error (see Demo plnkr), which is telling me that creating the empty function first and filling it later does not work:

使用这种方法,我得到的错误是以下错误(参见Demo plnkr),它告诉我先创建空函数,然后再填充它,这是无效的:

TypeError: Cannot read property 'then' of undefined
    at Scope.$scope.close (app.js:7:35)

What is the correct way to mock a service that has a function that returns a promise?

模拟具有返回承诺的函数的服务的正确方法是什么?

1 个解决方案

#1


2  

First of all, make mock service method return Promise object:

首先,使模拟服务方法返回承诺对象:

mock__mdSidenav = function(component) {
  return {
    isMock: true, 
    close: function() {
        return $q.when();
    }
  }
};

Then inject it into controller instance:

然后注入控制器实例:

menuCtrl = $controller("MenuCtrl", { 
    $scope: $scope,
    $mdSidenav: mock__mdSidenav
});

And finally, write some expectation:

最后,写下一些期望:

it('should create the $mdSidenav object', function() {

  $scope.close();
  $rootScope.$digest();

  expect($scope.closed).toBe(true);
});

Demo: http://plnkr.co/edit/dr79GgZYG2tjiuWU0oFx?p=preview

演示:http://plnkr.co/edit/dr79GgZYG2tjiuWU0oFx?p=preview

#1


2  

First of all, make mock service method return Promise object:

首先,使模拟服务方法返回承诺对象:

mock__mdSidenav = function(component) {
  return {
    isMock: true, 
    close: function() {
        return $q.when();
    }
  }
};

Then inject it into controller instance:

然后注入控制器实例:

menuCtrl = $controller("MenuCtrl", { 
    $scope: $scope,
    $mdSidenav: mock__mdSidenav
});

And finally, write some expectation:

最后,写下一些期望:

it('should create the $mdSidenav object', function() {

  $scope.close();
  $rootScope.$digest();

  expect($scope.closed).toBe(true);
});

Demo: http://plnkr.co/edit/dr79GgZYG2tjiuWU0oFx?p=preview

演示:http://plnkr.co/edit/dr79GgZYG2tjiuWU0oFx?p=preview