Тестирование сервисов $resource в AngularJS
Я пытаюсь начать писать модульные тесты для моего приложения angular и довольно быстро ударить блок остановки, так как я не уверен, как точно издеваться над моим сервисом с возможностью тестирования.
Есть ли способ издеваться над вызовом REST, иначе мне показалось бы, что мне нужно отразить все в моей службе в моих тестах, что для меня не кажется правильным, но я довольно новичок в тестировании, так что, возможно, так оно и есть которые должны быть выполнены. Любая помощь будет принята с благодарностью.
Мой сервис выглядит следующим образом:
angular.module('resources.users', ['ngResource'])
.factory('User', function($resource) {
var resource = $resource('/api/index.php/users/:username', {}, {
'update': {method: 'PUT'}
});
resource.getUser = function(username, successCb) {
return resource.query({username: username}, successCb);
};
return resource;
});
Мой тест состоит из:
describe('User', function() {
var mockUserResource;
beforeEach(module('resources.users'));
beforeEach(function() {
mockUserResource = sinon.stub({
getUser: function(username) {
mockUserResource.query({username: username});
},
query: function() {}
});
module(function($provide) {
$provide.value('User', mockUserResource);
})
});
describe('getUser', function() {
it('should call getUser with username', inject(function(User) {
User.getUser('test');
expect(mockUserResource.query.args[0][0]).toEqual({username: 'test'});
}));
})
});
Ответы
Ответ 1
Вы можете высмеивать запросы, сделанные ngResource следующим образом:
describe('User', function () {
var mockUserResource, $httpBackend;
beforeEach(angular.mock.module('myApp'));
beforeEach(function () {
angular.mock.inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
mockUserResource = $injector.get('User');
})
});
describe('getUser', function () {
it('should call getUser with username', inject(function (User) {
$httpBackend.expectGET('/api/index.php/users/test')
.respond([{
username: 'test'
}]);
var result = mockUserResource.getUser('test');
$httpBackend.flush();
expect(result[0].username).toEqual('test');
}));
});
});
Демо
Ответ 2
ответ zsong очень помог мне понять это, но я хотел бы рассказать о том, как это работает. Если он будет отредактирован, я снова перечислил код:
describe('User', function () {
var mockUserResource, $httpBackend;
beforeEach(angular.mock.module('myApp'));
beforeEach(function () {
angular.mock.inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
mockUserResource = $injector.get('User');
})
});
describe('getUser', function () {
it('should call getUser with username', inject(function (User) {
$httpBackend.expectGET('/api/index.php/users/test')
.respond([{
username: 'test'
}]);
var result = mockUserResource.getUser('test');
$httpBackend.flush();
expect(result[0].username).toEqual('test');
}));
});
});
Что происходит здесь?
1
beforeEach(angular.mock.module('myApp'));
Сообщаем инжектору Angular ($injector
и angular.mock.inject
) для ввода объектов, определенных в модуле myApp
. Вы можете думать об этом как об определении зависимости модуля без зависимого модуля. Сравните с тем, как вещи, определенные в модуле myApp
, могут быть введены, скажем, в контроллере в модуле angular.module('myOtherApp', ['myApp'])
.
2
beforeEach(function () {
angular.mock.inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
mockUserResource = $injector.get('User');
})
});
Перед каждой спецификацией запустите функцию function ($injector)
с введенными зависимостями. В этом случае зависимость ($injector
) неявно разрешена из имени параметра. Функционально эквивалентным вариантом этого фрагмента является
beforeEach(function () {
angular.mock.inject(['$httpBackend', 'User', function ($httpB, User) {
$httpBackend = $httpB;
mockUserResource = User;
}]);
});
Здесь мы явно объявляем зависимости явно и можем использовать любые имена параметров, которые мы хотим.
3
it('should call getUser with username', inject(function (User) {
Опять же, тестовой функции вводится неявно разрешенная служба User
как параметр, хотя она фактически не используется.
Обратите внимание, что на этот раз нет функции обертки вокруг вызова inject
. inject
немедленно запускает переданную функцию, если спецификация в настоящее время запущена, но в противном случае она возвращает функцию-оболочку (см. вложенный docs и исходный код), поэтому нам действительно не нужна функция обертки. Таким образом, мы могли бы написать фрагмент beforeEach
выше:
beforeEach(angular.mock.inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
mockUserResource = $injector.get('User');
}));