简体   繁体   English

如何在控制器中对一个函数进行单元测试(使用Jasmine),该控制器调用返回promise的工厂服务

[英]How to unit test (using Jasmine) a function in a controller which calls a factory service which returns a promise

In the below SampleController , how do I unit test that postAttributes function calls sampleService.updateMethod . 在下面的SampleController中 ,我如何对postAttributes函数调用sampleService.updateMethod进行单元测试。 I'm having trouble since the updateMethod returns promise. 我遇到麻烦,因为updateMethod返回了promise。

    angular.module('sampleModule')
       .controller('SampleController', SampleController);

    SampleController.$inject =['sampleService'];

    function SampleController(sampleService){

    this.postAttributes = function() {    
        sampleService.updateMethod(number,attributes)
            .then(function(response){
                //do something on successful update
            },function(response){
                //do something on unsuccessful update
            });
        }; 

    }

Here is the factory service that I have: 这是我的工厂服务:

    angular.module('sampleModule')
        .factory('sampleService', sampleService);

    sampleService.$inject = ['$http'];

    function sampleService($http) {
        return {
            getMethod: function(acctNumber){
                return $http({
                    method: 'GET',
                    url: //api endpoint
                });
            },
            updateMethod: function(number, attributes){
                return $http({
                    method: 'PUT',
                    url: //api endpoint,
                    data: //payload
                });
            }
        };
    }

I would like to mock the factory service in the controller spec rather than injecting the actual service directly into $controller, since most of unit testing guidelines specify to test a unit under isolation. 我想在控制器规范中模拟工厂服务,而不是直接将实际服务注入$ controller,因为大多数单元测试指南都指定在隔离下测试一个单元。

Sample controller spec: 样本控制器规范:

    describe('SampleController Test', function(){
        var $controller;
        var service;

        beforeEach(angular.mock.module('sampleModule')); 

        beforeEach(angular.mock.inject(function(_$controller_){
            $controller = _$controller_;
        }));

        it('Testing $scope variable', function(){
            var sampleController = $controller('SampleController', { 
                sampleService: service, //mocked factory service 
            });

            sampleController.postAttributes(); //calling the function first
            //here I would like to make an assertion to check if
            //sampleService.updateMethod has been called with certain parameters                        
            //how do I do that??
        });

    });

Googled around and found a solution to mock the factory service and followed promise creation approach like @TehBeardedOne and made it to return it from the mocked service. 谷歌搜索并找到一个模拟工厂服务的解决方案,并遵循像@TehBeardedOne这样的承诺创建方法,并让它从模拟服务返回它。

    describe('SampleController', function(){

        var mockService, controller, deferred, $rootScope;

        beforeEach(function(){

            angular.mock.module('sampleModule');

            angular.mock.module(function($provide){
                $provide.factory('sampleService', function($q){
                    function updateMethod(acct, attr){
                        deferred = $q.defer();
                        return deferred.promise;
                    }
                    return{updateMethod: updateMethod};
                });
            });

            angular.mock.inject(function($controller, sampleService, _$rootScope_){
                $rootScope = _$rootScope_;
                mockService = sampleService;
                spyOn(mockService, 'updateMethod').and.callThrough();
                controller =$controller('SampleController', {
                    sampleService: mockService,
                })
            });
        });

        it('postAttributes function should call updateMethod', function(){

            controller.postAttributes();
            expect(mockService.updateMethod).toHaveBeenCalled();
            expect(mockService.updateMethod).toHaveBeenCalledWith(controller.accountNumber, controller.attributes);
        });

        it('postAttributes success block', function(){
            controller.postAttributes();
            var res = {
                data: '2323'
            }
            deferred.resolve(res);
            $rootScope.$digest();
            expect(//something in success block).toBe(something);
        });

        it('postAttributes failure block', function(){
            controller.postAttributes();
            var res = {
                data: '9898'
            }
            deferred.reject(res);
            $rootScope.$digest();
            expect(controller.lame).toBe('dont type shit');
        });

    });

I've mocked the sampleService with $provider service and made updateMethod to return a promise using $q . 我嘲笑与$提供商的服务sampleService并提出updateMethod返回使用$ Q的承诺。 Later on you can resolve or reject the promise and test the success and failure blocks in individual it blocks. 稍后,您可以解决或拒绝承诺并测试其阻止的单个成功和失败块。

You will need to use a spy to check that the function is being called. 您将需要使用间谍来检查是否正在调用该函数。 There are several ways to go about doing this as I'm sure you have probably already noticed. 有几种方法可以做到这一点,因为我相信你可能已经注意到了。 You also need to inject $q and $rootScope as you will need to loop the digest cycle in order to return the promise. 你还需要注入$q$rootScope因为你需要循环摘要周期才能返回promise。

In fact, if all you want to do is check that the function is being called a simple spy will work just fine. 事实上,如果你想做的就是检查函数是否被调用,一个简单的间谍就可以了。 You don't even have to return the promise. 你甚至不必退还承诺。 That being said, if you want to continue on through the postAttributes() function and test other stuff inside this function then you will need to return the promise to do that. 话虽这么说,如果你想继续通过postAttributes()函数并测试这个函数中的其他东西,那么你将需要返回承诺来做到这一点。 Here is the approach that works well for me. 这是适合我的方法。 Something like this should work. 这样的事情应该有效。

describe('SampleController Test', function(){
    var $controller;
    var service;
    var $q;
    var $rootScope;
    var updateMethodDeferred;
    var ctrl;
    var mockHttpObject;

    beforeEach(angular.mock.module('sampleModule'));

    beforeEach(angular.mock.inject(function(_sampleService_, _$q_, _$rootScope_, _$controller_){
        service = _sampleService_;
        $q = _$q_;
        $rootScope = _$rootScope_;
        $controller = _$controller_;

        mockHttpObject = {
            //add mock properties here
        }

        updateMethodDeferred = $q.defer();
        spyOn(service, 'updateMethod').and.returnValue(updateMethodDeferred.promise);

        ctrl = $controller('SampleController', {
            sampleService: service, //mocked factory service
        });
    }));

    it('Testing $scope variable', function(){
        ctrl.postAttributes();
        expect(service.updateMethod).toHaveBeenCalled();
    });

    it('Should do something after promise is returned', function(){
        ctrl.postAttributes();
        updateMethodDeferred.resolve(mockHttpObject);
        $rootScope.$digest();
        expect(/*something that happened on successful update*/).toBe(/*blah*/)           
    });
});

暂无
暂无

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

相关问题 如何使用Jasmine测试AngularJS控制器,该控制器调用返回promise的服务方法 - How to test with Jasmine an AngularJS controller that calls service method that returns promise 返回承诺Angularjs Jasmine的单元测试服务 - Unit test service that returns promise Angularjs Jasmine 单元测试角度控制器和服务使用哪个承诺? - Unit test an angular controller and service which uses a promise? 如何为依赖于工厂服务的控制器编写单元测试,工厂服务本身依赖于$ http服务 - How to write unit test for a controller that depends on a factory service which itself depends on the $http service 使用Jasmine对单元服务进行单元测试(非工厂) - Unit test an angular service (not factory) using Jasmine 如何使用承诺测试角度工厂函数是否在 jasmine 中引发错误 - How to test that an angular factory function using a promise is throwing an error in jasmine 测试Angular控制器使用Jasmine一次准确地调用服务功能 - Test Angular controller calls service function exactly once using Jasmine 如何测试返回promise $ q的函数? - How to test a function which returns a promise $q? 如何用$ resource测试在AngularJS中返回承诺的工厂? - How to test a factory with $resource which returns a promise in AngularJS? 如何监视调用另一个服务的服务函数并返回Promise-TypeScript - How to spy on a service function that calls another service which returns a promise - typescript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM