Может ли кто-нибудь поделиться опытом с просмотрами модулей тестирования? Я прочитал много уроков о том, как выполнять модульное тестирование с просмотрами, но все имеет некоторые недостатки.
Я пришел к следующему подходу. Это работает, но мне интересно, есть ли лучший способ сделать это. Есть также некоторые недостатки, которые я объясню позже. Я также делаю тесты E2E с транспортиром, но они всегда медленны, и поэтому я ограничу их до минимума.
Это мой контроллер. Он имеет две переменные, связанные с его $scope
, которые используются в представлении:
// test_ctrl.js
angular.module('app', [])
.controller('TestCtrl', ["$rootScope", "$scope", function ($rootScope, $scope) {
$scope.bar = "TEST";
$scope.jobs = [
{name: "cook"}
];
}]);
Вид принимает $scope.bar
в массив <span>
и $scope.jobs
в директиве ng-repeat
:
<!-- test.html the view for this controller -->
<span>
Bar is {{bar || "NOT SET"}}
</span>
<ul>
<li ng-repeat="job in jobs">{{job.name}}</li>
</ul>
И это тест:
describe('Controller: TestCtrl', function () {
beforeEach(module('templates'));
beforeEach(module('app'));
var TestCtrl, $rootScope, $compile, createController, view, $scope;
beforeEach(inject(function($controller, $templateCache, _$rootScope_, _$compile_, _$httpBackend_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$compile = _$compile_;
createController = function() {
var html = $templateCache.get('views/test.html');
TestCtrl = $controller('TestCtrl', { $scope: $scope, $rootScope: $rootScope });
view = $compile(angular.element(html))($scope);
$scope.$digest();
};
}));
it('should test the view', function() {
createController();
expect(view.find("li").length).toEqual(1)
console.log($scope.jobs)
});
});
В функции beforeEach
я настрою контроллер. Функция createController
(которая вызывается из самих тестов) выводит представление из $templateCache
, создает контроллер с собственным $scope
, затем компилирует шаблон и запускает a $digest
.
Кэш шаблонов предварительно заполняется препроцессором karmas ng-html2js
// karma.conf.js
...
preprocessors: {
'app/views/*.html': 'ng-html2js'
}
...
При таком подходе у меня есть небольшая проблема, и некоторые вопросы:
1. Дополнительные $$ ключи hashKey в моих объектах от ng-repeat
expect($scope.jobs).toEqual([{name: "cook"}]);
в моем тесте выдает ошибку:
Expected [ { name : 'cook', $$hashKey : '009' } ] to equal [ { name : 'cook' } ]
Я знаю, что ng-repeat
добавляет эти ключи, но это глупо тестировать. Единственный способ, о котором я могу думать, - это отделить тесты контроллера и тесты просмотра. Но когда я проверяю массив jobs
внутри моего контроллера, $$hashKey
нет. Любые идеи, почему это происходит?
2. $scope
Когда я впервые пробовал это, у меня была только локальная область, определенная как $scope={}
, а не $scope = $rootScope.$new()
, как это было в других тестах контроллера. Но с помощью простого объекта в качестве локальной области я не смог его скомпилировать ($compile(angular.element(html))($scope);
выбрал ошибку).
Я также подумал, что неплохо передать сам $rootScope
как текущую локальную область для контроллера. Это хороший подход? Или есть какие-то недостатки, я еще не видел?
3. Лучшие практики
Я был бы очень рад узнать, как все остальные проводят модульные тесты в AngularJS. Я думаю, что взгляды должны быть проверены, потому что со всеми директивами angular в них много логики, и я был бы рад видеть водонепроницаемый;)