使用 jasmine 对控制器中基于资源的工厂进行角度 js 单元测试
Posted
技术标签:
【中文标题】使用 jasmine 对控制器中基于资源的工厂进行角度 js 单元测试【英文标题】:angular js unit test using jasmine for a resource based factory in controller 【发布时间】:2016-07-27 18:31:12 【问题描述】:我是使用 jasmine 编写单元测试用例的新手。我正在尝试在控制器中测试基于资源的服务,该控制器从服务器获取真实数据但没有得到预期的结果。请在我做错的地方提供您的意见。下面是我写的单元测试: 描述('NewStarterController',函数() beforeEach(module('myApp')); var 范围,ctrl,$resource;
var context = 'http://localhost.com:8085/AngularPrototype/home';
beforeEach(inject(function(_$resource_, $rootScope, $controller)
$resource = _$resource_;
NewStarter =
getNSData : function()
return $resource(context + '/selfservice/newstarter/get', ,
get :
method : 'GET'
);
;
scope = $rootScope.$new();
$controller('NewStarterController',
$scope : scope,
NewStarter : NewStarter
);
));
it('should test new starter data', function()
NewStarter.getNSData().get().$promise.then(function(response)
scope.refData = response;
scope.data();
);
expect(scope.data.length).toEqual(2);
expect(NewStarter.getNSData().get.length).toEqual(2);
expect(NewStarter.getNSData().get()).toEqual('formTitleNode');
);
);
Below is the jasmine test result ::
Jasmine 1.3.1 revision 1354556913finished in 0.183s
•
No try/catchFailing 1 spec1 spec | 1 failing
NewStarterController
should test new starter data
NewStarterController should test new starter data.
Expected 0 to equal 2.
Expected 4 to equal 2.
Expected $promise : $$state : status : 0 , $resolved : false to equal 'formTitleNode'.
get.json -> represents the data that is returned from server(Data returned from RestController) on hitting the url : http://localhost.com:8085/AngularPrototype/home/selfservice/newstarter/get
SpecRunner.html-> is used to run the jasmine unit test. Below are the contents of this file :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Jasmine Demo</title>
<script>
libraries here
</script>
</head>
<body>
<!-- Include Angular and Angular Mocks-->
<script>libraries here </script>
<!-- Include your source files here... -->
<script src="services/services.js"></script>
<script src="myApp.js"></script>
<script src="controller/selfservice/NewStarterController.js"></script>
<!-- Include your spec files here... -->
<script src="jasmineunittest/NewStarterControllerTest.js"></script>
<!-- Jasmine execution script (Standard Jasmine Bolierplate)-->
<script type="text/javascript">
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.execute();
</script>
</body>
</html>
Below is the controller code ( NewStarterController.js ) which is unit tested :
myApp.controller("NewStarterController", ['$scope','$modal', '$state', '$sce', 'NewStarter', function($scope,$modal, $state, $sce, NewStarter)
$scope.data = function()
NewStarter.getNSData().get(, function(response)
$scope.refData = response;
$scope.formTitle = [];
$scope.displayOptions = [];
angular.forEach($scope.refData.formTitleNode, function(contentItem)
var content = -1;
var title = -1;
angular.forEach(contentItem.fieldList, function(fieldBean)
if(fieldBean.fieldName == 'TITLE')
title = fieldBean.fieldValue;
if(fieldBean.fieldName == 'FORMATTEDCONTENTS')
content = fieldBean.fieldValue;
)
$scope.formTitle.push(title:title, content:content);
)
angular.forEach($scope.refData.displayOptionsNode, function(contentItem)
var nsContent = -1;
var nsTitle = -1;
angular.forEach(contentItem.fieldList, function(fieldBean)
if(fieldBean.fieldName == 'TITLE')
nsTitle = fieldBean.fieldValue;
if(fieldBean.fieldName == 'FORMATTEDCONTENTS')
nsContent = fieldBean.fieldValue;
)
$scope.displayOptions.push(nsTitle:nsTitle, nsContent:nsContent);
$scope.selectedOption = '';
)
$scope.hasNewStarterSubmitted = $scope.refData.hasNewStarterSubmitted;
$scope.submittedSelectedOption = $scope.refData.submittedSelectedOption;
$scope.submittedStudentLoan = $scope.refData.submittedStudentLoan;
$scope.nsAlreadySubmittedValidationMsg = $scope.refData.nsAlreadySubmittedValidationMsg;
console.log('Success', response);
, function(error)
//alert(JSON.stringfy(error))
$scope.contentLoadErrorMsg=error.data;
//console.error('ERR', error);
);
]);
Below is the code in services.js
myApp.factory('NewStarter', function($resource, context)
return
getNSData: function()
return $resource(context + '/selfservice/newstarter/get', , get: method:'GET');
,
submitNSForm: function()
return $resource(context + '/selfservice/newstarter/submit', , submit: method:'POST');
);
Below is the code in myApp.js
var myApp = angular.module('myApp', ['ngResource', 'ngSanitize', 'ui.bootstrap', 'ui.router']);
myApp.constant('context', '/AngularPrototype/home');
myApp.constant('projectName', '/AngularPrototype');
myApp.config(function($stateProvider, $urlRouterProvider, projectName)
$urlRouterProvider.otherwise('/home');
$stateProvider .state('newStarter',
url:'/newstarter',
templateUrl: projectName + '/newstarter',
controller: 'NewStarterController'
)
);
Thanks!
Below i tried as per your suggestion but getting error while running the unit test:
describe('NewStarterController', function()
beforeEach(module('myApp'));
var scope, postDefer,NewStarter;
beforeEach(inject(function(_NewStarter_, $rootScope, $controller,$q)
NewStarter = _NewStarter_;
postDefer = $q.defer();
spyOn(NewStarter,'getNSData').and.returnValue(postDefer.promise);
scope = $rootScope.$new();
$controller('NewStarterController',
$scope : scope,
NewStarter : NewStarter
);
));
it('should test new starter data', function()
NewStarter.getNSData().get();
postDefer.resolve();
scope.$apply();
expect(scope.data.length).toEqual(2);
);
);
Below are the errors while running the test :
Error:[$injector:unpr] Unknown provider: NewStarterProvider <- NewStarter
typeError: Unable to get property 'getNSData' of undefined or null reference
【问题讨论】:
您的模拟 getNSData 不必调用 $resource,只需返回一个承诺,并在需要验证结果时解决该承诺。检查我对其他问题的回答***.com/questions/36189329/… 我按照您的建议进行了尝试,但没有成功。无法识别 getNSData 方法。可以分享一下代码吗??谢谢! 您能否根据我的建议使用您尝试过的代码更新您的问题? 用我尝试过的代码更新了问题,并提到了我在运行单元测试时遇到的错误。请查看并提供您的宝贵意见。谢谢! 【参考方案1】:由于是单元测试,需要重点测试单个单元,尽量mock所有依赖。话虽如此,在单元测试中使用真正的 $resource 是不可取的。
我认为你应该做的是:- 1. 模拟 NewStarter.getNSData(),或在控制器中调用的任何服务方法 2.返回一个伪造的资源对象 3. 模拟假资源的 get 方法(因为它是在你的控制器中使用的)并返回一个承诺 4. 兑现承诺以测试您的成功处理程序。
看看这个笨蛋http://plnkr.co/edit/8l3mY1?p=preview
var mockResource = get: function(), $q;
beforeEach(inject(function($rootScope, $controller, _$q_, NewStarter)
$scope = $rootScope.$new();
$q = _$q_;
spyOn(NewStarter, 'getNSData').and.callFake(function()
return mockResource;
);
ctrl = $controller('MainCtrl',
$scope: $scope
);
));
it('should return value', function()
var responseObj = id: 1, name:'test';
spyOn(mockResource, 'get').and.callFake(function(data, func)
var deferred = $q.defer();
deferred.resolve(responseObj);
return deferred.promise.then(func);
);
$scope.data();
expect(mockResource.get).toHaveBeenCalled();
$scope.$apply();
expect($scope.refData).toEqual(responseObj);
);
【讨论】:
以上是关于使用 jasmine 对控制器中基于资源的工厂进行角度 js 单元测试的主要内容,如果未能解决你的问题,请参考以下文章
在 Jasmine 单元测试中模拟 AngularJS 模块依赖项
如何对 AngularJS $promise.then 进行单元测试