类似的问题:Jasmine angularjs - spying on a method that is called when controller is initialized
在我的控制器中,我使用angular-local-storage包通过注入提供localStorageService。
在我的单元测试中,我想确保从服务中检索数据,因此我会监视" get"和"添加"方法并模拟它们(.andCallFake)。
这适用于通过$ scope调用的所有方法。$ watch - 只要我强制$ digest。但是对于在控制器初始化时调用的方法,它似乎不起作用。 任何人都可以建议为什么这不起作用?
应用> 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);
};
}]);
试验> 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);
});
除了构造函数中的那个之外,所有测试都通过了:
expect(localStorageService.get).toHaveBeenCalledWith('todos');
答案 0 :(得分:5)
原因是控制器在您调用$controller
的位置初始化,在您的示例中之前您通过spyOn
创建了间谍。您的示例的解决方案是在对$controller
的调用之后将调用移至spyOn
。
对于较长的测试套件,为了保持干净,您可能必须将$controller
的呼叫置于单独的功能中,然后您可以在模拟任何所需的服务后进行呼叫。
答案 1 :(得分:3)
更新了测试套件,确保在调用控制器构造函数之前 <:>
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);
});
});
答案 2 :(得分:1)
您还需要在beforeEach()调用中包含LocalStorageModule,以便在test.js文件中加载模块。
beforeEach(module('angularTodoApp', 'LocalStorageModule'));
另外,不要忘记更新你的karma.conf.js文件
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'
],
//...
我只是偶然发现了同样的问题,这对我来说很有用。
最后,如果您使用Jasmine 2.4并spyOn(...).andCallFake(...)
spyOn(...).and.callFake(...)
来电
之前答案中给出的方法在Jasmine 2.4中不起作用(尽管未在以前的版本中测试过)。