#angularjs #unit-testing #asynchronous #jasmine #karma-jasmine
#angularjs #модульное тестирование #асинхронный #jasmine #карма-жасмин
Вопрос:
Я не могу передать результат теста, я использую очень простую реализацию, чтобы глубже понять тестирование.
У меня есть фабрика, которая возвращает обещание, доступ к которому осуществляется с моего контроллера. Я хочу проверить, что вызов выполнен успешно и присваивает ответ repos
переменной. Ниже приведен код:
'use strict';
angular.module('app')
.factory('searchServ', function ($timeout, $q, $http) {
return {
fetch: function(user) {
var deferred = $q.defer();
$timeout(function(){
$http({method: 'GET', url: 'https://api.github.com/users/' user '/repos'}).then(function(repos) {
deferred.resolve(repos.data);
}, function(reason){
deferred.reject(reason.status);
console.log(reason);
});
}, 30);
return deferred.promise;
}
};
})
.controller('MainCtrl', function ($scope, searchServ) {
$scope.results = function(user) {
$scope.message = '';
searchServ.fetch(user).then(function (repos) {
if(repos.length){
$scope.message = '';
$scope.repos = repos;
}
else{
$scope.message = 'not found'
}
}, function (){
$scope.message = 'not found';
});
};
});
//Test
'use strict';
describe('MainCtrl', function () {
var scope, searchServ, controller, deferred, repos = [{name: 'test'}];
// load the controller's module
beforeEach(module('app'));
beforeEach(inject(function($controller, $rootScope, $q) {
searchServ = {
fetch: function () {
deferred = $q.defer();
return deferred.promise;
}
};
spyOn(searchServ, 'fetch').andCallThrough();
scope = $rootScope.$new();
controller = $controller('MainCtrl', {
$scope: scope,
fetchGithub: fetchGithub
});
}));
it('should test', function () {
expect(scope.test).toEqual('ha');
});
it('should bind to scope', function () {
scope.results();
scope.$digest();
expect(scope.message).toEqual('');
//expect(scope.repos).not.toBe(undefined);
});
});
Запуск теста выдает следующую ошибку :
TypeError: undefined is not a function (evaluating 'spyOn(searchServ, 'fetch').andCallThrough()') in test/spec/controllers/main.js (line 15)
Есть идеи, как я могу протестировать это так, чтобы оно проверяло привязку области видимости, а также асинхронный вызов?
Комментарии:
1. Нет
andCallThrough
. Это такand.callThrough
. Вы широко используете отложенный антипаттерн . Что в вашем случае обернется плохо. Потому что searchServ.fetch возвращает неразрешенное обещание в вашем случае.2. Я пробовал вызов and.callThrough, но он всегда возвращает undefined, я также пробовал другой подход, например, эту скрипку jsfiddle.net/upoc0ott/2 но все равно остается неопределенным, было бы удивительно, если бы кто-нибудь мог мне помочь, используя любой из способов?
Ответ №1:
В вашем коде много проблем.
Я создал этот Plunkr для этой цели. index.js
это файл с вашим кодом и тестовыми примерами. Я отредактировал большую часть части в соответствии с соглашениями и рекомендациями.
Есть несколько советов, которые я хотел бы вам дать:
- Поскольку
$http
возвращает обещание, вы должны использовать это вместо разрешения обещания и создания другого обещания из вашего метода. Не уверен, почему используется тайм-аут. Поэтому я удалил$q
и$timeout
изsearchServ
зависимостей. - Я сделал то же самое в тестовом примере, удалив
deferred
переменную, которую вы использовали. - Вы должны использовать
angular-mocks.js
для моделирования своих сервисов и других зависимостей вместо определения сервиса внутри вашего тестового примера (как вы это сделали).) - Вы должны создать отдельные
describe
блоки для тестирования разных частей вашего кода (controller
в данном случае a).
Надеюсь, это поможет!
Комментарии:
1. Это был блестящий ответ! Большое спасибо, что нашли время. Я использовал $ timeout и $ q, потому что они основаны на обещаниях, и если вы создадите фабрику / сервис через yeoman, это даст вам такой подход, но поскольку $ http также возвращает обещание, я думаю, что это работает так же хорошо! 🙂