API Angular Service Calls в конструкторе - Жасмин Тест - PullRequest
0 голосов
/ 30 ноября 2018

Мой сервис одноэлементный, и в своем конструкторе он вызывает функцию для вызова API.Это прекрасно работает, когда служба инициализируется, так как снижает сложность и импорт, необходимый для вызова этих приложений, запускает API.Кроме того, это делает службу независимой, поскольку ей не нужно полагаться на, скажем, AppComponent для импорта и вызова функций Api.

Создание службы Singleton при загрузке приложения: app.module.ts

....

export class AppModule {

  constructor(private applicationSettings: ApplicationSettings) {

  }
}

...

Служба: application-settings.ts

import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ApplicationSettings{

  ...

  constructor( private httpClient: HttpClient ){
    this.LoadSettings();
  }

  private LoadSettings() {
    this.httpClient.get<any>(this.settingsApiUrl, { observe: 'response' })
    .pipe(
      retry(3)
    ).subscribe(
      data => this.ApiSuccess(data),
      error => this.ApiError(error)
    );
  }

  ...

}

Модульный тест: application-settings.spec.ts

import { ApplicationSettings } from './application-settings.service';
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { environment } from '@environments/environment';

let applicationSettings;
let httpMock: HttpTestingController;
let settingsApiUrl = environment.ApplicationSettings;

describe('ApplicationSettings', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        ApplicationSettings
      ],
      imports: [
        HttpClientTestingModule
      ]
    });
  });

  beforeEach(() => {
    applicationSettings = TestBed.get(ApplicationSettings);
    httpMock = TestBed.get(HttpTestingController);

    // Attempt to catch from constructor
    httpMock.expectOne({
      url: settingsApiUrl,
      method: 'get'
    }).flush({});


    httpMock.verify();
  });

  describe('Tests To Pass', () => {
    fit('should create the app', () => {
      expect(applicationSettings).toBeDefined();
    });

    fit('should be successfull and call ApiSuccess', () => {
      spyOn(applicationSettings, 'ApiSuccess');

      httpMock.expectOne({
        url: settingsApiUrl,
        method: 'get'
      }).flush({});

      applicationSettings.LoadSettings();

      expect(applicationSettings.ApiSuccess).toHaveBeenCalled();
    });

    ...
  });
});

При выполнении моих тестовых случаев иногда они работают, но в 80% случаевони выбросят ошибку.Один тест может бросить 1, другой 3, а другой может быть 5 (не обязательно в таком порядке:

[object ErrorEvent] thrown
[object ErrorEvent] thrown
[object ErrorEvent] thrown

, а также будет сказано:

Error: Expected one matching request for criteria "Match method: get, URL: //localhost/api/appSettings", found none.

Если я удаляю httpMock.expectOne в основном BeforeEach() (у меня есть комментарий к этой строке, указывающий на попытку перехватить конструктор). Затем каждый тест будет проходить через эту ошибку:

Expected no open requests, found 1: GET //localhost/...

Я на 100% уверен, что это связано с APIвызовите конструктор, насколько мне известно, каждый создаваемый им тест и использует новый экземпляр службы AppSettings, который, в свою очередь, вызовет функцию API LoadSettings.

Как и прежде, чем я переместил вызов в конструктор, всеиспытания проходили.

1 Ответ

0 голосов
/ 30 ноября 2018

После всестороннего тестирования я обнаружил, что проблема была в том, как я заботился о том, что LoadSettings () APi вызывается из конструктора.Правильный способ реализации:

beforeEach(() => {
  applicationSettings = TestBed.get(ApplicationSettings);
  httpMock = TestBed.get(HttpTestingController);

  // Catches the call from the constructor
  httpMock.expectOne({
    url: settingsApiUrl,
    method: 'get'
  });

  httpMock.verify();
});

Основная концепция была правильной до того, как я удалил .flush({}), и он работает нормально.Из моего чтения flush определение определено следующим образом: здесь :

Имитирует асинхронное прохождение времени для таймеров в зоне fakeAsync путем опустошения очереди макротасков допустой.Возвращаемое значение - это миллисекунды времени, которые были бы пройдены.

Я думаю, что происходило до того, как каждый произойдет до того, как будет выполнен каждый тест, и flush() каким-то образом принимал запросы httpиз очереди, вызывающей фатальные проблемы.Во время теста.Или при наличии сброса он предотвращал вызов API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...