Я борюсь с модульным тестированием контроллера, который следит за парой переменных. В моих модульных тестах я не могу получить обратный вызов для вызова функции $watch, даже при вызове scope.$digest(). Кажется, это должно быть довольно просто, но мне не повезло.
Вот что у меня есть в моем контроллере:
angular.module('app')
.controller('ClassroomsCtrl', function ($scope, Classrooms) {
$scope.subject_list = [];
$scope.$watch('subject_list', function(newValue, oldValue){
if(newValue !== oldValue) {
$scope.classrooms = Classrooms.search(ctrl.functions.search_params());
}
});
});
И вот мой модульный тест:
angular.module('MockFactories',[]).
factory('Classrooms', function(){
return jasmine.createSpyObj('ClassroomsStub', [
'get','save','query','remove','delete','search', 'subjects', 'add_subject', 'remove_subject', 'set_subjects'
]);
});
describe('Controller: ClassroomsCtrl', function () {
var scope, Classrooms, controllerFactory, ctrl;
function createController() {
return controllerFactory('ClassroomsCtrl', {
$scope: scope,
Classrooms: Classrooms
});
}
// load the controller's module
beforeEach(module('app'));
beforeEach(module('MockFactories'));
beforeEach(inject(function($controller, $rootScope, _Classrooms_ ){
scope = $rootScope.$new();
Classrooms = _Classrooms_;
controllerFactory = $controller;
ctrl = createController();
}));
describe('Scope: classrooms', function(){
beforeEach(function(){
Classrooms.search.reset();
});
it('should call Classrooms.search when scope.subject_list changes', function(){
scope.$digest();
scope.subject_list.push(1);
scope.$digest();
expect(Classrooms.search).toHaveBeenCalled();
});
});
});
Я попытался заменить все вызовы scope.$digest() на вызовы scope.$apply(). Я пытался позвонить им 3 или 4 раза, но я не могу получить обратный вызов $watch для вызова.
Любые мысли о том, что может происходить здесь?
ОБНОВЛЕНИЕ: Вот еще более простой пример, в котором не используются макеты, заглушки или внедрения фабрик.
angular.module('edumatcherApp')
.controller('ClassroomsCtrl', function ($scope) {
$scope.subject_list = [];
$scope.$watch('subject_list', function(newValue, oldValue){
if(newValue !== oldValue) {
console.log('testing');
$scope.test = 'test';
}
});
И модульный тест:
it('should set scope.test', function(){
scope.$digest();
scope.subject_list.push(1);
scope.$digest();
expect(scope.test).toBeDefined();
});
Это также не работает с «Ожидается, что неопределенное будет определено». и ничего не записывается в консоль.
ОБНОВЛЕНИЕ 2
Еще 2 интересные вещи я отметил.
Похоже, одна из проблем заключается в том, что newValue и oldValue совпадают при вызове обратного вызова. Я зарегистрировал оба в консоли, и они оба равны []. Итак, например, если я изменю свою функцию $watch, чтобы она выглядела так:
$scope.$watch('subject_list', function(newValue, oldValue){ console.log('testing'); $scope.test = 'test'; });
тест проходит нормально. Не уверен, почему новые значения и старые значения не устанавливаются правильно.
Если я изменю свою функцию обратного вызова $watch на именованную функцию и просто проверю, вызывалась ли когда-либо именованная функция, это также не удастся. Например, я могу изменить свой контроллер на это:
$scope.update_classrooms = function(newValue, oldValue){ $scope.test = 'testing'; console.log('test'); }; $scope.watch('subject_list', $scope.update_classrooms);
И измените мой тест на это:
it('should call update_classrooms', function(){
spyOn(scope,'update_classrooms').andCallThrough();
scope.$digest();
scope.subject_list.push(1);
scope.$digest();
expect(scope.update_classrooms).toHaveBeenCalled();
});
он завершается с ошибкой «Ожидается, что был вызван шпионский update_classrooms».
В этом случае update_classrooms определенно вызывается, потому что в консоли регистрируется «test». Я сбит с толку.
expect(Classrooms.search).toHaveBeenCalled()
, но не вижу, где настроен этот шпион. Что за сообщение об ошибке? - person ivarni   schedule 09.07.2014