如何对控制器中的函数进行单元测试(使用 Jasmine),该函数调用 returns 承诺的工厂服务
How to unit test (using Jasmine) a function in a controller which calls a factory service which returns a promise
在下面的 SampleController 中,我如何对 postAttributes[=28 进行单元测试=]函数调用sampleService.updateMethod。自 updateMethod returns 承诺以来我遇到了麻烦。
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
});
}
};
}
我想在控制器规范中模拟工厂服务,而不是将实际服务直接注入 $controller,因为大多数单元测试指南都指定在隔离下测试单元。
示例控制器规格:
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??
});
});
您将需要使用间谍程序来检查是否正在调用该函数。有几种方法可以做到这一点,我相信您可能已经注意到了。您还需要注入 $q
和 $rootScope
,因为您需要循环摘要循环才能 return 承诺。
事实上,如果您只想检查函数是否被调用,一个简单的间谍就可以正常工作。您甚至不必 return 承诺。也就是说,如果您想继续执行 postAttributes()
函数并测试此函数中的其他内容,那么您将需要 return 承诺这样做。这是适合我的方法。这样的东西应该可以工作。
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*/)
});
});
Google 搜索并找到了一个模拟工厂服务的解决方案,并遵循像@TehBeardedOne 这样的承诺创建方法,并从模拟服务中 return 它。
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');
});
});
我用 $provider 服务模拟了 sampleService 并制作了 updateMethod 到 return 使用 $q 的承诺。稍后您可以解决或拒绝承诺并在单个 it 块中测试成功和失败块。
在下面的 SampleController 中,我如何对 postAttributes[=28 进行单元测试=]函数调用sampleService.updateMethod。自 updateMethod returns 承诺以来我遇到了麻烦。
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
});
}
};
}
我想在控制器规范中模拟工厂服务,而不是将实际服务直接注入 $controller,因为大多数单元测试指南都指定在隔离下测试单元。
示例控制器规格:
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??
});
});
您将需要使用间谍程序来检查是否正在调用该函数。有几种方法可以做到这一点,我相信您可能已经注意到了。您还需要注入 $q
和 $rootScope
,因为您需要循环摘要循环才能 return 承诺。
事实上,如果您只想检查函数是否被调用,一个简单的间谍就可以正常工作。您甚至不必 return 承诺。也就是说,如果您想继续执行 postAttributes()
函数并测试此函数中的其他内容,那么您将需要 return 承诺这样做。这是适合我的方法。这样的东西应该可以工作。
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*/)
});
});
Google 搜索并找到了一个模拟工厂服务的解决方案,并遵循像@TehBeardedOne 这样的承诺创建方法,并从模拟服务中 return 它。
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');
});
});
我用 $provider 服务模拟了 sampleService 并制作了 updateMethod 到 return 使用 $q 的承诺。稍后您可以解决或拒绝承诺并在单个 it 块中测试成功和失败块。