admin管理员组文章数量:1352849
Similar question to: Jasmine angularjs - spying on a method that is called when controller is initialized
In my controller I use the angular-local-storage package to provide a localStorageService through injection.
in my unit tests I want to make sure the data is retrieved from the service, so I spy on the "get" and "add" methods and mock them (.andCallFake).
this works fine with all the methods that are called through $scope.$watch - as long as I force a $digest. but for the method that is called on the controller initialization, it does not seem to work. Can anyone advise why this doesn't work?
app>Main.js
angular.module('angularTodoApp')
.controller('MainCtrl',['$scope','localStorageService',function ($scope, localStorageService) {
var todosInStore = localStorageService.get('todos');
$scope.todos = todosInStore && todosInStore.split('\n') || [];
//$scope.todos = ['Item 1', 'Item 2', 'Item 3'];
$scope.$watch('todos', function(){
localStorageService.add('todos', $scope.todos.join('\n'));
},true);
$scope.addTodo = function() {
$scope.todos.push($scope.todo);
$scope.todo = '';
};
$scope.removeTodo = function(index) {
$scope.todos.splice(index,1);
};
}]);
test>Main.js
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularTodoApp'));
var MainCtrl,
scope,
localStorageService,
store = [];
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
scope = $rootScope.$new();
localStorageService = _localStorageService_;
MainCtrl = $controller('MainCtrl', {
$scope: scope,
localStorageService: _localStorageService_
});
//mock localStorageService get/add
spyOn(localStorageService,'get').andCallFake(function(key){
return store[key];
});
spyOn(localStorageService,'add').andCallFake(function(key, val){
store[key] = val;
});
}));
it('should retrieve "todos" from the store and assign to scope', function () {
expect(localStorageService.get).toHaveBeenCalledWith('todos');
expect(scope.todos.length).toBe(0);
});
it('should add items to the list and update the store for key = "todos"', function () {
scope.todo = 'Test 1';
scope.addTodo();
scope.$digest();
expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
expect(scope.todos.length).toBe(1);
});
all tests pass except the one in the constructor:
expect(localStorageService.get).toHaveBeenCalledWith('todos');
Similar question to: Jasmine angularjs - spying on a method that is called when controller is initialized
In my controller I use the angular-local-storage package to provide a localStorageService through injection.
in my unit tests I want to make sure the data is retrieved from the service, so I spy on the "get" and "add" methods and mock them (.andCallFake).
this works fine with all the methods that are called through $scope.$watch - as long as I force a $digest. but for the method that is called on the controller initialization, it does not seem to work. Can anyone advise why this doesn't work?
app>Main.js
angular.module('angularTodoApp')
.controller('MainCtrl',['$scope','localStorageService',function ($scope, localStorageService) {
var todosInStore = localStorageService.get('todos');
$scope.todos = todosInStore && todosInStore.split('\n') || [];
//$scope.todos = ['Item 1', 'Item 2', 'Item 3'];
$scope.$watch('todos', function(){
localStorageService.add('todos', $scope.todos.join('\n'));
},true);
$scope.addTodo = function() {
$scope.todos.push($scope.todo);
$scope.todo = '';
};
$scope.removeTodo = function(index) {
$scope.todos.splice(index,1);
};
}]);
test>Main.js
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularTodoApp'));
var MainCtrl,
scope,
localStorageService,
store = [];
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
scope = $rootScope.$new();
localStorageService = _localStorageService_;
MainCtrl = $controller('MainCtrl', {
$scope: scope,
localStorageService: _localStorageService_
});
//mock localStorageService get/add
spyOn(localStorageService,'get').andCallFake(function(key){
return store[key];
});
spyOn(localStorageService,'add').andCallFake(function(key, val){
store[key] = val;
});
}));
it('should retrieve "todos" from the store and assign to scope', function () {
expect(localStorageService.get).toHaveBeenCalledWith('todos');
expect(scope.todos.length).toBe(0);
});
it('should add items to the list and update the store for key = "todos"', function () {
scope.todo = 'Test 1';
scope.addTodo();
scope.$digest();
expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
expect(scope.todos.length).toBe(1);
});
all tests pass except the one in the constructor:
expect(localStorageService.get).toHaveBeenCalledWith('todos');
Share
Improve this question
edited May 23, 2017 at 11:59
CommunityBot
11 silver badge
asked Apr 13, 2014 at 22:10
Vincent De SmetVincent De Smet
4,9792 gold badges36 silver badges41 bronze badges
3 Answers
Reset to default 5The reason is that the controller is initialised at the point you call $controller
, which in your example is before you're created the spies via spyOn
. The solution for your example is to move the call to $controller
to after the calls to spyOn
.
For longer test suites, to keep things DRY, you might have to put the call to $controller
in a separate function, that you can then call after you have mocked up any required services.
Updated test suite, make sure mocks are in place before calling controller constructor:
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularTodoApp'));
var MainCtrl,
scope,
localStorageService,
store;
// Initialize the controller and mocks
beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
store = []; //clear the store before each test
scope = $rootScope.$new();
localStorageService = _localStorageService_;
//mock localStorageService get/add
spyOn(localStorageService,'get').andCallFake(function(key){
return store[key];
});
spyOn(localStorageService,'add').andCallFake(function(key, val){
store[key] = val;
});
//Instantiate controller to test
MainCtrl = $controller('MainCtrl', {
$scope: scope,
localStorageService: localStorageService
});
}));
it('should retrieve "todos" from the store and assign to scope', function () {
expect(localStorageService.get).toHaveBeenCalledWith('todos');
expect(scope.todos.length).toBe(0);
});
it('should add items to the list and update the store for key = "todos"', function () {
scope.todo = 'Test 1';
scope.addTodo();
scope.$digest();
expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
expect(scope.todos.length).toBe(1);
});
it('should remove items to the list and update the store', function() {
scope.todo = 'Test 1';
scope.addTodo();
scope.$digest();
//reset call count
localStorageService.add.reset();
scope.removeTodo(0);
scope.$digest();
expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
expect(scope.todos.length).toBe(0);
});
});
You also need to include the LocalStorageModule in your beforeEach() call for loading the module in test.js file.
beforeEach(module('angularTodoApp', 'LocalStorageModule'));
Also, don't forget to update your karma.conf.js file
module.exports = function(config) {
// ...
files: [
'/path/to/angular.min.js',
'/path/to/angular-mocks.js',
'/path/to/angular-local-storage.js',
'Main/test.js',
'Main/app.js'
],
//...
I just stumbled on the same problem, this did the trick for me.
Finally, you also need to modify the spyOn(...).andCallFake(...)
call if you're using Jasmine 2.4 with spyOn(...).and.callFake(...)
The method given in the previous answers is not working in Jasmine 2.4 (not tested in previous versions though).
本文标签:
版权声明:本文标题:javascript - Jasmine angularjs - spying on angular-local-storage methods called when controller is initialized - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743914619a2561002.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论