Unit test для вложенных контроллеров
Я пытаюсь написать unit test для контроллера, который вложен, но не может понять, как издеваться над тем же поведением в моем тесте.
У меня есть 2 контроллера:
function FirstController ($scope) {
$scope.childs = [{
title : 'Hello, earth!'
}];
};
function SecondController ($scope) {
$scope.child.title = $scope.child.title + $scope.$index;
};
И в моем HTML:
<div data-ng-controller="FirstController">
<div data-ng-repeat="child in childs" data-ng-controller="SecondController">
{{ child.title }}
</div>
</div>
И это работает как ожидалось (http://jsfiddle.net/tcayp/1/)
Унитесты:
// FirstController
it('Should have childs', function () {
scope = {};
ctrl = new FirstController(scope);
expect(scope.childs.length).toBeGreaterThan(0);
});
// SecondController
it('Should have inherited a child', function () {
scope = {};
ctrl = new SecondController(scope);
expect(scope.child.title).toEqual('Hello, earth!0');
});
В SecondController-test я не могу понять, как издеваться над цепочкой наследования от ng-repeat.
Ответы
Ответ 1
В идеале, при единичных тестах мы хотели бы изолировать классы (единицы). Контроллер 2 в одном тесте может быть слишком большим: тест станет более сложным и более хрупким.
Более подробно рассмотрим приведенный пример, можно заметить, что на самом деле это не касается тестирования 2 контроллеров, а скорее обеспечения доступности данных в родительской области. Поэтому, сосредоточив внимание только на одном контроллере (SecondController
) и наследуемых данных, вы должны написать такой тест:
describe('Testing the SecondController controller', function() {
var $parentScope, $scope, ctrl;
it('should prepare title', inject(function($rootScope, $controller) {
//setup hierarchy of scopes with data
$rootScope.childs = [{
title : 'Hello, earth!'
}];
$scope = $rootScope.$new();
$scope.$index = 1;
ctrl = $controller('SecondController', {
$scope: $scope
});
expect($scope.childs[0].title).toEqual('Hello, earth!1');
}));
});
Вот полный jsFiddle: http://jsfiddle.net/pkozlowski_opensource/h8xry/13/
Я бы посоветовал не тестировать два контроллера вместе, а только для ответа на вопрос, возможно также:
describe('Testing the SecondController controller', function() {
it('should prepare title', inject(function($rootScope, $controller) {
$controller('FirstController', {
$scope: $rootScope
});
var $scope = $rootScope.$new();
$scope.$index = 1;
ctrl = $controller('SecondController', {
$scope: $scope
});
expect($scope.childs[0].title).toEqual('Hello, earth!1');
}));
});
И jsFiddle: http://jsfiddle.net/pkozlowski_opensource/4Qy6b/1/
Ответ 2
Документация AngularJS предлагает протестировать вложенные контроллеры, создав экземпляр каждого из них и установив одну и ту же иерархию областей между ними, как в вашем приложении. Это имеет смысл, потому что (до точки) вы хотите проверить свой контроллер в реалистичном контексте.
Ответ 3
В тестовом экземпляре родительский контроллер с новой областью действия:
mainScope = $rootScope.$new();
$controller('ParentController', {$scope: mainScope});
и в вашем дочернем контроллере создайте экземпляр новой области с использованием ранее созданной области:
childScope = mainScope.$new();
$controller('ChildController', {$scope: childScope});
Пример из Документация AngularJS:
describe('state', function() {
var mainScope, childScope, grandChildScope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
$controller('MainController', {$scope: mainScope});
childScope = mainScope.$new();
$controller('ChildController', {$scope: childScope});
grandChildScope = childScope.$new();
$controller('GrandChildController', {$scope: grandChildScope});
}));
it('should have over and selected', function() {
expect(mainScope.timeOfDay).toBe('morning');
expect(mainScope.name).toBe('Nikki');
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbread Baby');
});
});