У меня есть такая угловая фабрика:
.factory('widgetFactory', ['$http', function($http){
function getWidgets(){
return $http.get('http://example.com/api/widgets/')
.then(function(response){
return response;
});
}
return {
getWidgets:getWidgets
};
}])
А у меня есть такой жасминовый тест:
describe('widgetFactory', function ($q) {
var mockHttp,
fakeResponse = 'response'
beforeEach(function() {
mockHttp = {
get: jasmine.createSpy('get spy').and.callFake(function () {
var deferred = $q.defer();
deferred.resolve(fakeResponse);
return deferred.promise;
})
};
module(function ($provide) {
$provide.value('$http', mockHttp);
});
});
it('should call api when getWidgets is called', inject(function (widgetFactory) {
var result;
widgetFactory.getWidgets().then(function(response){
result = response;
});
expect(mockHttp.post).toHaveBeenCalledWith('http://example.com/api/widgets/');
expect(result).toBe(fakeResponse);
}));
});
Но я получаю следующую ошибку: description не ожидает параметра done .
Я думаю, это может быть связано с тем, как я использую $ q в своем тесте (в других примерах, которые я видел, есть inject(function($q){ ...
внутри beforeEach
, но я не могу из-за того, что использую module
внутри beforeEach
, так как это дает мне следующую ошибку: Инжектор уже создан, не удается зарегистрировать модуль!)
Любые идеи?
2 ответа
Вы не можете ввести метод описания. Здесь я переработал вашу версию, чтобы использовать ngMock
и избавиться от mockHttp. Надеюсь, это немного объясняет, как работает ngMock
describe('widgetFactory', function () {
var mockHttp,
fakeResponse = 'response',
getWidgetsDefer,
getWidgetsPromise,
$httpBackend,
widgetFactory,
$q;
beforeEach(module('plunker'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$q = $injector.get('$q');
widgetFactory = $injector.get('widgetFactory');
}));
beforeEach(function() {
getWidgetsDefer = $q.defer();
$httpBackend.when('GET', 'http://example.com/api/widgets/')
.respond(getWidgetsDefer);
getWidgetsPromise = widgetFactory.getWidgets();
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should call api when getWidgets is called', inject(function (widgetFactory) {
expect($httpBackend.flush).not.toThrow();
}));
});
Вы можете найти плункер здесь
Функция 'done' - это аргумент, который ожидается в блоках Jasmine, но не в describe
, в этом смысл ошибки. Сервисы Angular не могут быть внедрены без оболочки inject
, потому что Жасмин не знает о них, и проблема не может быть решена, просто игнорируя этот факт.
angular.mock.module
может имитировать службы с аргументом объекта a>, нет необходимости заново изобретать колесо.
К сожалению, имитируемые сервисы должны быть самодостаточными, и это не решит проблему с $q
, поэтому его нужно добавить дополнительно после module
:
var $q;
beforeEach(function() {
module({
$http: { ... }
});
inject(function (_$q_) {
$q = _$q_;
});
})
К счастью, ngMock предоставляет макет $ httpBackend, так что насмешка $http
- это бессмысленно. Фактически, настоящий запрос не должен (и не может) выполняться с помощью ngMock. Спецификация службы виджетов становится такой же тонкой:
widgetFactory.getWidgets();
$httpBackend.expect('GET', 'http://example.com/api/widgets/').respond(fakeResponse);
expect($httpBackend.flush).not.toThrow();
Обратите внимание, что не имеет значения, был ли запрос имитирован до или после вызова $http.get
, запросы решаются при вызове $httpBackend.flush()
. И проверку fakeResponse === fakeResponse
тоже можно спокойно пропустить.
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript/JS) и его различных диалектах/реализациях (кроме ActionScript). Обратите внимание, что JavaScript — это НЕ Java. Включите все теги, относящиеся к вашему вопросу: например, [node.js], [jQuery], [JSON], [ReactJS], [angular], [ember.js], [vue.js], [typescript], [стройный] и т. д.