Тестирование asyn c HTTP-функции с помощью Jasmine и await: ожидался один соответствующий запрос по критерию «...», не найдено ни одного - PullRequest
0 голосов
/ 25 мая 2020

ЧТО: Тестирование функции asyn c, которая использует await

WITH: Angular 9, Jasmine 3.4.0

Минимальный код для воспроизведения: StackBlitz

У меня есть такая функция. Обратите внимание, что он должен ждать this.getHeaders (). Всякий раз, когда я удаляю ожидание и заменяю реализацию getHeaders () какой-нибудь синхронной реализацией, тест выполняется успешно.

Как правильно его протестировать?

private async loadUserData() {
    // Try to remove await - the test runs successfully
    //const headers = this.getHeaders();
    const headers = await this.getHeaders();
    return this.httpClient
      .get<UserData>(window.location.origin + '/12345', { headers })
      .toPromise()
      .then((data) => {
        this.userData = data;
      })
      .catch((e) => {
        console.log('Oh noooo...');
      });
  }

ЧТО Я TRIED:

  • Возможно, URL-адрес в StackBitz неверен, но при локальном тестировании я уверен, что это так, поэтому это не должно быть root причиной
  • не уверен, поможет ли fakeAsyn c () - "чистый" http тест работает ...

НЕ ДУПЕР:

1 Ответ

1 голос
/ 26 мая 2020

Вы очень близки. Теперь ваш тест структурирован правильно, но вам нужны некоторые утилиты тестирования, предоставляемые Angular, чтобы убедиться, что ваши обещания выполняются в правильном порядке, чтобы ваши ожидания были правильными.

В конечном итоге проблема связана с Angular зоны. Потому что вы структурируете обещания в своей службе, и разрешение этого обещания должно произойти до того, как произойдет исходящий запрос. Вы вызываете loadUserData в своем тесте, а затем в следующей строке вы пишете утверждение, в котором говорится: «Убедитесь, что этот запрос произошел, если это не ошибка». Когда вы пишете функцию получения заголовка таким образом, чтобы не использовать примитив asyn c (например, Promise или Observable), этот запрос выполняется «немедленно». Но когда вы используете Promise, никакой запрос не происходит «сразу». Вместо этого он должен сначала разрешить вашу функцию извлечения заголовка.

К счастью, ваш тестовый сбой - всего лишь фантомная функция тестовой среды, а не ошибка в вашей реализации. Как я уже сказал, Angular дает вам некоторые инструменты для тестирования, чтобы убедиться, что вы можете «проверить sh» все ожидающие обещания перед написанием утверждения.

import { fakeAsync,  tick } from '@angular/core/testing';

// instead of using `done`, which is just fine btw, we wrap our test function
// in fakeAsync(). This let's us have fine grained control over stepping through
// our code under test
it('should return user data on success', fakeAsync(() => {
  const mockUserData : UserData = {
    name: 'John',
      surname: 'Do',
      id: '12345'
    };

    (service as any).loadUserData().then(() => {
      expect((service as any).userData).toEqual(mockUserData);
      //expect(req.request.method).toEqual('GET');
    });

    // tick() steps through the next round of pending asynchronous activity
    // this will also step through 'setTimeout' and 'setInterval' code
    // you may have in your service, as well as Observable code
    tick();
    const req = httpTestingController.expectOne(
      'https://testing-qh48mg.stackblitz.io/12345',
    );
    req.flush(mockUserData);
}));

Обновлено Stackblitz . Документы на fakeAsync. Связанный вопрос по тестированию Http-кода в Angular с использованием tick.

...