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

Jod*_*odi 4 unit-testing timeout rxjs jasmine-marbles

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

堆栈闪电战

待测管道:

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

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

expect(await source.toPromise()).toEqual({ timeout: true });
Run Code Online (Sandbox Code Playgroud)

用茉莉花大理石测试

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

因错误而失败

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 }) }).
Run Code Online (Sandbox Code Playgroud)

sen*_*ico 5

最近在 jasmine-marbles 0.5.0 中添加了对时间进程的支持(参见 jasmine-marbles PR #38)。额外的测试规范被添加到包中,展示了完成你想要的事情的几种可能方法之一。以下是我可以使用您的 Stackblitz 示例拼凑起来的一些选项。

选项1

当您在测试方法之外(例如 in beforeEach)初始化源 observable 时,您必须显式初始化并传递测试调度程序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);
  });
});
Run Code Online (Sandbox Code Playgroud)

选项 2

您可以稍微重构一下,并在测试方法(而不是in beforeEach)中初始化源 observable 。您不需要显式初始化测试调度程序(jasmine-marbles 会在测试方法运行之前为您完成),但您仍然必须将它传递给timeout. 请注意该createSource函数如何与测试调度程序或默认调度程序一起使用(如果scheduler参数为 left 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);
  });
});
Run Code Online (Sandbox Code Playgroud)

选项 3

最后,timeout如果您明确使用测试调度程序的run方法,您可以跳过将测试调度程序传递到,但您必须使用expectObservable(与 . 相反expect().toBeObservable()。它工作得很好,但 Jasmine 会报告警告“SPEC HAS NO EXPECATIONS”。

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 }]);
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

  • 看起来时间进程仍在融入`jasmine-marbles` 中。我想我会插入`rxjs-marbles`。很好的使用体验。它支持 Jasmine(以及其他),并且他们为各种用例收集了大量示例。https://github.com/cartant/rxjs-marbles/tree/master/examples (2认同)