Подтвердить что ты не робот

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, но в примере есть тестирование контроллера и просто материал, который изменяется в области $, когда запросы сделаны и возвращены. Есть ли способ достичь тестов, которые я хочу? Или я собираюсь что-то не так?

4b9b3361

Ответ 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
  });

});

С хорошей структурой кода даже наследование на самом деле не является проблемой, имея возможность иметь мелкозернистый контроль над тем, что должно быть издевательством, и что должно использоваться из исходного кода.