AngularJS: Как мне заглушить функцию внутри контроллера, который я тестирую?
У меня есть контроллер, который в настоящее время вызывает RESTful API при загрузке соответствующего представления. Поэтому я не уверен, связана ли эта проблема с тем, как я тестирую, или с реализацией самого кода - я был бы рад любым предложениям, которые будут решать проблему целостным образом, то есть помочь мне тестовый код, который делает то, что я хочу:)
Вот несколько примеров, иллюстрирующих мою точку зрения:
Контроллер:
angular.module('app.myModule',[])
.controller('MyController', function($scope) {
$scope.notTestingThis = function() {
var thisFails = $scope.do.not.want.to.mock.these.objects.substr(0,10);
};
$scope.testingThis = function(myString) {
$scope.newString = myString;
};
$scope.notTestingThis();
});
Тест (как есть):
describe('MyControllerTest', function() {
beforeEach(module('app.myModule'));
var $controller;
beforeEach(inject(function(_$controller_) {
$controller = _$controller_;
}));
describe('$scope.testingThis()', function() {
it('sets newString', function() {
$scope = {
'notTestingThis': {}
};
var myController = $controller('MyController', {$scope: $scope});
});
});
});
При загрузке этого представления мне нужно как-то вызвать функцию notTestingThis, однако в моем модульном тесте я хочу изолировать функцию testingThis. Проблема в том, что когда я инициализирую контроллер в моем тесте, он, конечно, вызовет notTestingThis и попытается выполнить действия с несуществующими объектами (и которые мне не нужны в этом тесте).
Очевидно, что попытка заглушить рассматриваемую функцию в соответствии с этим примером бесполезна, так как $ scope будет переписан при инициализации. Есть ли способ заглушить или смоделировать отдельные функции в контроллере, который вы пытаетесь проверить, или я где-то упустил суть? Некоторые предложения, которые выдвинул коллега:
Улучшите контроллер, чтобы он знал о самом модульном тесте, позволяя вам регулировать поток программ на основе введенного макета, то есть что-то вроде следующего в контроллере:
if (!$scope.methodA) {
$scope.methodA = function() {...}
}
... или же...
Измените способ вызова функции notTestingThis, прослушивая событие инициализации из $ rootScope, а не вызывая его напрямую, что позволило бы мне посмеяться над $ rootScope, чтобы он не вызывал это событие, предотвращая тем самым вызов notTestingThis
Я не могу не чувствовать, что думаю об этом неправильно. Есть идеи?
1 ответ
Просто удвоить ответ на этот вопрос на случай, если другие придут к нему. Я просмотрел обе рекомендации, реализовав обе с некоторыми отличиями от моих первоначальных комментариев (поскольку я неправильно понял рекомендации), а именно:
Опция 1
Вместо того, чтобы переносить каждую функцию, оберните вызывающий код в:
if(!testingBoolean) { $scope.notTestingThis(); };
С параметром testingBoolean false, если он не передан в качестве (необязательного) аргумента контроллеру, что позволяет коду тестирования предотвращать вызовы
Вариант 2:
$ широковещательная рассылка от $rootScope с использованием сервисной функции. Оберните вызывающий код в слушателе этого события, а затем вызовите функцию из контроллера. Насмешка над $rootScope при выполнении тестов предотвратит запуск функции notTestingThis.
Реальное решение
Эти подходы, похоже, отвлекают; хотя это нигде явно не указано, похоже, что контроллеры не должны сами вызывать функции. Правильный путь здесь заключается в том, чтобы изменить архитектуру приложения так, чтобы директивы вызывали функции через привязки, упрощая тем самым модульное тестирование.