如何使用jasmine-marbles测试rxjs管道中的timeout()

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用jasmine-marbles测试rxjs管道中的timeout()相关的知识,希望对你有一定的参考价值。

我编写了一个过滤输入observable的管道。在管道中,我使用timeout()运算符指定超时,如果源未及时发出预期值,则中止等待。我想用jasmine-marbles测试超时情况,但我无法让它工作。我相信expect(source).toBeObservable()会在源发出之前进行评估。

Stackblitz

要测试的管道:

source = cold('a', { a: { id: 'a' } }).pipe(
  timeout(500),
  filter((a) => false),
  catchError((err) => {
    return of({ timeout: true })
  }),
  take(1)
);

使用toPromise()进行测试按预期工作:

expect(await source.toPromise()).toEqual({ timeout: true });

用茉莉花大理石测试

const expected = cold('500ms (a|)', { a: { timeout: true } });
expect(source).toBeObservable(expected);

因错误而失败

Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'N', value: Object({ timeout: true }), error: undefined, hasValue: true }) }).
Expected $[1] = undefined to equal Object({ frame: 500, notification: Notification({ kind: 'C', value: undefined, error: undefined, hasValue: false }) }).
答案

最近增加了对时间进展的支持(see jasmine-marbles PR #38)到茉莉花大理石0.5.0。在软件包中添加了其他测试规范,演示了实现所需内容的几种可能方法之一。以下是我使用Stackblitz示例拼凑的一些选项。

选项1

在测试方法之外初始化源observable时(例如在beforeEach中),必须显式初始化并将测试调度程序传递给timeout以使expect().toBeObservable()正常工作。但是,请注意,此更改将打破“应该使用toPromise”测试。 (我不知道为什么,但toPromise()似乎不适用于这种方法。)

describe('Marble testing with timeout', () => {

  let source;

  beforeEach(() => {
    // You must explicitly init the test scheduler in `beforeEach`.
    initTestScheduler()
    source = cold('a', { a: { id: 'a' } }).pipe(
      // You must explicitly pass the test scheduler.
      timeout(500, getTestScheduler()),
      filter((a) => false),
      catchError(err => {
        return of({ timeout: true })
      }),
      take(1)
    );
  });

  it('should work with toBeObservable', () => {
    const expected = cold('500ms (a|)', { a: { timeout: true } });
    expect(source).toBeObservable(expected);
  });
});

选项2

您可以稍微重构一下并初始化测试方法中的源可观察对象(而不是在beforeEach中)。您不需要显式初始化测试调度程序(jasmine-marbles将在测试方法运行之前为您执行此操作),但您仍然必须将其传递给timeout。请注意createSource函数如何与测试调度程序或默认调度程序一起使用(如果scheduler参数保留为undefined)。此选项适用于“应该使用toPromise”测试和“应该使用toBeObservable”测试。

describe('Marble testing with timeout', () => {

  const createSource = (scheduler = undefined) => {
    return cold('a', { a: { id: 'a' } }).pipe(
      // You must explicitly pass the test scheduler (or undefined to use the default scheduler).
      timeout(500, scheduler),
      filter((a) => false),
      catchError(err => {
        return of({ timeout: true })
      }),
      take(1)
    );
  };

  it('should work with toPromise', async () => {
    const source = createSource();
    expect(await source.toPromise()).toEqual({ timeout: true });
  });

  it('should work with toBeObservable', () => {
    const source = createSource(getTestScheduler());
    const expected = cold('500ms (a|)', { a: { timeout: true } });
    expect(source).toBeObservable(expected);
  });
});

选项3

最后,如果你明确使用测试调度程序的timeout方法,你可以跳过将测试调度程序传递给run,但你必须使用expectObservable(而不是expect().toBeObservable()。它工作得很好,但是Jasmine会报告警告“SPEC没有预期”)。

describe('Marble testing with timeout', () => {

  let source;

  beforeEach(() => {
    source = cold('a', { a: { id: 'a' } }).pipe(
      timeout(500),
      filter((a) => false),
      catchError(err => {
        return of({ timeout: true })
      }),
      take(1)
    );
  });

  it('should work with scheduler and expectObservable', () => {
    const scheduler = getTestScheduler();
    scheduler.run(({ expectObservable }) => {
      expectObservable(source).toBe('500ms (0|)', [{ timeout: true }]);
    });
  });
});

以上是关于如何使用jasmine-marbles测试rxjs管道中的timeout()的主要内容,如果未能解决你的问题,请参考以下文章

如何用茉莉弹珠测试对象

如何使用 Jest 测试 Rxjs 空操作符

如何对正在进行的 RXJS 请求的取消进行单元测试

如何在 Angular 中使用 Jasmine 测试 RxJS switchMap?

rxjs-marbles 测试没有任何期望

typescript 使用rxjs的大理石测试和jsverify