Проверьте вызов метода внутри подписки rxjs - PullRequest
0 голосов
/ 09 октября 2019

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

Структура выглядит примерно так:

private obs$: Observable<T>;
private subscription: Subscription;

methodToTest(): void {
  this.obs$ = from( ... ).then( /* chain of piped observables */ );
  this.subscription = this.obs$
    .subscribe(
        (value: T) => {
          // bunch of logic
          methodToBeVerifiedWasCalled();
        },
        (error) => { /* error handling */ }
    );
}

Пока мой тест выглядит так:

it('the method to be verified is successfully called', () => {
  // various mocking set up
  this.mockApi.methodThatReturnsAPromise.and.returnvalue(Promise.resolve());
  // etc.

  this.classUnderTest.methodToTest();

  // assertions for the various mocks...
  expect(this.mockApi.methodThatReturnsAPromise).toHaveBeenCalled();
  // etc.

  // assert that the target method was called:
  expect(this.classUnderTest.methodToBeVerifiedWasCalled).toHaveBeenCalled();
  expect(this.classUnderTest.subscription).toBeDefined();
});

Конечно, этот тест завершается неудачно при последних утверждениях, потому что methodToBeVerifiedWasCalled фактически вызывается внутри блока подписки, и тест просто проходит через него синхронно. (Здесь classUnderTest - это шпионский объект, за которым следят methodToBeVerifiedWasCalled.)

Поскольку метод присваивает значение наблюдаемой, я не могу просто подписаться на classUndertest.obs$ в асинхронном тесте ипроверить возвращаемое значение (что на самом деле не помогает решить проблему). Как проверить, что вызывается метод внутри блока подписки?

Не могу изменить исходный код, только тесты.

1 Ответ

1 голос
/ 09 октября 2019

Вам нужно сделать свой тест асинхронным, а затем ждать что-то после methodToTest(). Если methodToTest() не возвращает обещание или наблюдаемое, которое вы могли бы ожидать, то вы будете вынуждены просто ждать, пока не пройдет какое-то время. Что-то вроде:

function delay(ms) {
  return new Promise(resolve => setTimeout(ms, resolve));
}

it('the method to be verified is successfully called', async (done) => {
  // various mocking set up
  this.mockApi.methodThatReturnsAPromise.and.returnvalue(Promise.resolve());
  // etc.

  const result = this.classUnderTest.methodToTest();
  // if the method actually returned a promise you could: await result;
  // since it does not, you can just await time:
  await delay(1000); // wait 1 second

  // assertions for the various mocks...
  expect(this.mockApi.methodThatReturnsAPromise).toHaveBeenCalled();
  // etc.

  // assert that the target method was called:
  expect(this.classUnderTest.methodToBeVerifiedWasCalled).toHaveBeenCalled();
  expect(this.classUnderTest.subscription).toBeDefined();

  // tell jasmine test is done
  done();
});
...