Основываясь на рекомендациях Руководства по стилю Angular (а также основных рекомендациях по объектно-ориентированному стилю), всякий раз, когда мне приходится взаимодействовать с веб-API, я реализую определенный класс, который обертывает Angular Http service, но добавляет любую пользовательскую конфигурацию, аутентификацию, проверку. или любые другие правила, необходимые для взаимодействия с этим API. Другими словами, я создаю класс ApiGateway class.

Однако мне было трудно понять, как именно провести тест-драйв моего ApiGateway. Существуют примеры того, как использовать MockBackend для предоставления собственных ответов на ваши сервисы, чтобы вы могли видеть, как они взаимодействуют с результатами вашего веб-API, фактически не обращаясь к нему (см. https://blog.thoughtram.io /angular/2016/11/28/testing-services-with-http-in-angular-2.html для отличного примера), но для ApiGateway itself вся цель тестирования должна заключаться в том, чтобы убедиться, что он правильно вызывает в службу Http Angular с правильной информацией. Мой тест других служб данных может использовать фиктивные результаты, но ApiGateway заключается в правильном использовании Http service, поэтому для меня это должно быть в центре внимания тестов.

Так, например, мой универсальный ApiGateway будет иметь в основном 2 метода:

  • get(url: string, params: any)
  • post(url: string, params: any, data: any)

В этих методах ApiGateway будет отвечать за добавление соответствующих заголовков для аутентификации и настройку соответствующего базового URL-адреса для использования, чтобы другим службам не приходилось заниматься этим.

Таким образом, мое тестирование в первую очередь связано с тем, чтобы при использовании любого из этих методов результирующий запрос был правильно настроен.

Настройка тестовой среды

Первым шагом является настройка тестовой среды таким образом, чтобы служба Http больше не выполняла фактические запросы XHR, а вместо этого использовала фиктивную реализацию. Реализуя это, вы можете перехватывать эти запросы XHR и проверять их, а также при необходимости предоставлять свои собственные результаты.

import {ApiGateway} from './api-gateway.service';
import {async, inject, TestBed} from '@angular/core/testing';
import {BaseRequestOptions, Http, HttpModule, Request, RequestMethod, RequestOptions, Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';

describe('ApiGateway', () => {
  let apiGateway: ApiGateway,   mockBackend: MockBackend;
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpModule ],
      providers: [
        ApiGateway,
        {
           provide: Http,
           useFactory:(_mockBackend: MockBackend, options: RequestOptions) => {
             return new Http(_mockBackend,options);
           },
           deps: [MockBackend, BaseRequestOptions]
        },
        MockBackend,
        BaseRequestOptions,
      ]
    });
  });
 beforeEach(inject([ApiGateway, MockBackend],
           (_apiGateway: ApiGateway, _mockBackend: MockBackend) => {
   apiGateway = _apiGateway;
   mockBackend = _mockBackend;
 }));
.....

Конфигурация выше указана более подробно из статьи thoughtram. Опять же, ознакомьтесь со статьей — в ней здорово все настроить правильно.

Ключевое отличие состоит в том, что меня больше интересует тестирование того, как мой ApiGateway взаимодействует с сервисом Http Angular. (Http хорошо протестирован командой Angular, поэтому я могу с уверенностью предположить, что если я правильно вызову его, он будет вести себя правильно.)

Определение вашего поведения

describe('get()', () => {
  let request: Request;
  let connection: MockConnection;
  beforeEach(async(() => {
    // grab the mock connection and request to inspect them later
    mockBackend.connections.subscribe((c: MockConnection) => {
      connection = c;
      request = c.request;
    }); 
  }));
  it("requests the correct url", () => {
    let url = "accounts";
    apiGateway.get(url).subscribe();
    expect(request.url).toContain(url, 'requests the correct url');
  });
  it("makes a 'GET' request", () => {
    apiGateway.get('hello').subscribe();
    expect(request.method).toEqual(RequestMethod.Get);
  });
  it('makes a request to the url', async(() => {
    let mockResponse = [
      {id: 0, name: 'Account 0'},
      {id: 1, name: 'Account 1'},
      {id: 2, name: 'Account 2'},
      {id: 2, name: 'Account 2'},
    ];
    apiGateway.get('random').subscribe(accounts => {
         expect(accounts.length).toEqual(4, '4 accounts returned');
    });
    let response = new Response( 
         new ResponseOptions({body: JSON.stringify(mockResponse)}));
      connection.mockRespond(response);
    }));
});

Обратите внимание, что в блоке beforeEach я хватаюсь за объект Request , прикрепленный к блоку MockConnection. Этот Request object представляет мое взаимодействие с Http service.

Если у вас есть ссылка на этот объект Request , проверить правильность выполнения запроса будет несложно. Главное помнить, что Request не существует до тех пор, пока вы не подпишетесь на Http observable.

Последний пример показывает, что вы можете сделать, предоставив фиктивный ответ. Главное, что здесь проверяется, это то, что результаты службы Http service правильно преобразуются в JSON.

Итак, после проб и ошибок я теперь могу проверить, правильно ли мой ApiGateway взаимодействует с моим веб-API через Http service.

Утилиты тестирования Angular довольно мощные, но к ним нужно привыкнуть, поэтому я надеюсь, что это поможет следующему человеку, который придет.