AngularJS - метод тестирования, который использует службу $http
У меня есть функция на моем сервисе, которая выглядит примерно так:
addStatement: function(user, action, object) {
var statement = {
user: user,
action: action,
object: object
};
$http({
method: 'POST',
url: '/foo/bar',
data: statement,
headers: {Authorization: 'Basic YWxhZGRpbjpvcGVuIHNlc2FtZQ=='}
}).success(function(data) {
alert("success: " + data);
});
}
Я хочу написать unit test для этого метода, но я не уверен, как заставить его работать. В принципе, я хочу проверить, что отправленные данные были правильно построены из параметров функции и что был отправлен правильный заголовок авторизации.
Я читал о том, как использовать $httpBackend, но в примере есть тестирование контроллера и просто материал, который изменяется в области $, когда запросы сделаны и возвращены. Есть ли способ достичь тестов, которые я хочу? Или я собираюсь что-то не так?
Ответы
Ответ 1
Службы тестирования не сильно отличаются от контрольных контроллеров, поэтому принципы одинаковы. В основном вам необходимо:
- Объекты, находящиеся в процессе тестирования
- setup mocks (если есть) - здесь вы были на правильном пути, используя $httpBackend mock
- запустить методы на проверяемом объекте и проверить результаты
Если вы после тестирования, что методы службы приводят к вызову $http POST, вы можете написать свой тест следующим образом (несущественные части опущены):
beforeEach(module('MyApp'));
beforeEach(inject(function(MyService, _$httpBackend_) {
service = MyService;
$httpBackend = _$httpBackend_; // angular strips the underscores so
// we don't need to use unique names
// https://docs.angularjs.org/api/ngMock/function/angular.mock.inject
}));
it('should invoke service with right paramaeters', function() {
$httpBackend.expectPOST('/foo/bar', {
"user": "testUser",
"action": "testAction",
"object": {}
}, function(headers){
return headers.Authorization === 'Basic YWxhZGRpbjpvcGVuIHNlc2FtZQ==';
}).respond({});
service.addStatement('testUser', 'testAction', {});
$httpBackend.flush();
});
Вот рабочий jsFiddle, иллюстрирующий этот тест в действии: http://jsfiddle.net/pkozlowski_opensource/MkrjZ/2/
Последнее замечание: лучше не использовать .alert() в модульных тестах, так как эти предупреждения приостанавливают выполнение тестов.
Ответ 2
Я написал сообщение в блоге об этой самой теме, рассказывающей немного об использовании angular встроенных макетов и написании собственных макетов, возможно, это поможет вам получить более глубокое понимание:
Как издеваться над модулями AngularJS и вводить их в тестовые тесты?
Вкратце он определяет второй модуль для тестирования, который может высмеять желаемое поведение:
var apptastic = angular.module('apptastic', []),
apptasticMock = angular.module('apptasticMock', []);
И перезаписывает исходное поведение, например. например:
apptasticMock.service("socket", function($rootScope){
... // overwrite
});
Затем он должен быть загружен в тесты - это работает, потому что angular перезаписывает уже определенные службы в том порядке, в котором они загружены:
describe("Socket Service", function(){
var socket;
beforeEach(function(){
module('apptastic');
module('apptasticMock');
inject(function($injector) {
socket = $injector.get('socket');
});
});
it("tests something", function(){
... // test
});
});
С хорошей структурой кода даже наследование на самом деле не является проблемой, имея возможность иметь мелкозернистый контроль над тем, что должно быть издевательством, и что должно использоваться из исходного кода.