4

在下面的工厂服务SampleController,我怎么单元测试postAttributes函数调用sampleService .update方法。自updateMethod返回诺言以来,我遇到了麻烦。如何单元测试(使用茉莉花)在控制器中的函数调用,它返回一个承诺

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

    } 

这里是工厂的服务,我有:

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

我想嘲笑控制器规范的工厂服务,而不是直接注入实际的服务为$控制器,因为大多数单位测试指南指定在隔离状态下测试一个单元。

样品控制器规格:

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

    }); 

回答

3

周围一派,找到了解决嘲笑厂服,跟着像@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'); 
     }); 

    }); 

我嘲笑sampleService$提供商服务并取得updateMethod返回使用$ Q的承诺。稍后,您可以解决或拒绝承诺,并测试单个块中的成功和失败块。

1

您将需要使用间谍来检查函数被调用。有几种方法可以做到,因为我相信你可能已经注意到了。您还需要注入$q$rootScope,因为您需要循环摘要循环才能返回承诺。

事实上,如果你想要做的只是检查函数被调用的简单间谍将工作得很好。你甚至不必退还承诺。这就是说,如果你想继续通过postAttributes()函数并测试这个函数中的其他东西,那么你将需要返回承诺来做到这一点。这是对我来说很好的方法。像这样的东西应该工作。

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*/)   
    }); 
}); 
+0

尝试了上述方法,但后来发现** sampleService **本身具有很多依赖性。因此,如果我必须遵循上述方法,那么我需要注入sampleService的所有依赖关系,应该是这种情况,因为我们测试的只是控制器,我们应该嘲笑所有的依赖关系。目前我试图用$ provide.factory来模拟服务。我该如何从成功和错误模块的模拟服务中返回承诺? – Pramodh

+0

我不知道为什么你还需要注入服务的依赖关系。我从来没有这样做,我的一些服务也有一些依赖。在任何情况下,您都可以使用deferred.resolve()命中您的成功块,并使用deferred.reject()命中您的错误块。 – tehbeardedone

相关问题