Angular - модульное тестирование обещания при построении компонента - PullRequest
0 голосов
/ 06 апреля 2020

Предположим, что конструктор и вызов функции следующего компонента:

constructor(private fooService: FooService){
    this.getBarFromService()
}

getBarFromService = () => fooService.getBar().then(bar => this.bar = bar)

И грубо сделанная getBar() функция сервиса, которая должна ждать результата API:

getBar() {
    let bar = null;
    await new Promise((resolve, reject) => {
        this.barBuilder.get('/bar').then(
            data => resolve(bar = data),             // data = baz
            error => reject(error)
        )
    return bar;
}

Теперь я хочу попытаться написать модульный / интеграционный тест, чтобы определить, что компонент может запрашивать и отображать данные без вызова API. И из того, что я прочитал, мне нужно будет смоделировать сервис, чтобы он не вызывал barBuilder в реальности, а вместо этого сразу возвращал значение. Это привело к следующему тестовому файлу:

beforeEach(() =>{
    let mockFooService = jasmine.createSpyObj('FooService', ['getBar']);
    mockFooService.getBar.and.returnValue(Promise.resolve(baz))

    TestBed.configureTestingModule({
        providers: [{provide: FooService, useValue: mockFooService}],
    }).compileComponents();
});

describe('get bar should return baz', () => {
    expect(component).toBeTruthy();
    component.getBar();
    fixture.detectChanges();
    expect(component.bar).toBe(baz)
}

Поскольку исходная функция getBar() возвращает данные в разрешенном объекте обещания, а не сами данные, я должен воссоздать указанное разрешение, иначе тест будет не удалось сказать, что он не может обработать блок then() вызова. После этого он дал мне идею, что тест работает на функциональном уровне, поскольку тест продолжается, и я предполагаю, что действие в блоке then() было выполнено.

Однако значение baz не был применен к компоненту после создания и ручного вызова, и нет указателей, чтобы увидеть, где лежит ошибка. Случайное бросание console.log() между каждым ожиданием показывает, что component.bar остается нулевым в каждой точке. Я также не нашел правдоподобного ответа, как использование fakeAsync и так далее. не применяется, так как функция getBarFromService() сама по себе не является асинхронной.

Таким образом, я в растерянности, и документация как Angular (v8), так и Жасмин была сведена к букве ( лучше всего.)

Вопрос звучит; Как я могу найти, почему и где переменная baz не применяется к component.bar в макете и / или в самом модульном тесте, и как я смогу ее решить?

1 Ответ

0 голосов
/ 06 апреля 2020

Вы должны использовать async() и whenStable()

describe('get bar should return baz', async(() => {
  expect(component).toBeTruthy();
  component.getBar();
  fixture.detectChanges();

  fixture.whenStable().then(() => {
    expect(component.bar).toBe(baz);
  });
}));

. На заметке стороны ваш getBar может быть существенно упрощен до:

getBar() {
  return this.barBuilder.get('/bar');
}

.get метод уже возвращает обещание. Так что не нужно оборачивать это в new Promise. Если вы хотите иметь переменную bar внутри вашего метода, вы можете сделать это:

async getBar() {
  const bar = await this.barBuilder.get('/bar');

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