用开玩笑测试Observables

时间:2018-06-05 10:58:34

标签: rxjs observable jestjs

如何使用Jest测试Observable?

我有一个Observable每秒触发〜我想测试第一个事件是否正确触发,然后才开始出现。

const myObservable = timer(0, 1000); // Example here

it('should fire', () => {
  const event = myObservable.subscribe(data => {
    expect(data).toBe(0);
  });
});

这个测试通过,但如果我用toBe('anything')替换它也会通过,所以我猜我做错了。

我尝试使用expect.assertions(1),但它似乎只与Promises合作。

5 个答案:

答案 0 :(得分:4)

Jest文档中有一些很好的示例,它们为测试传递了一个参数。可以调用该参数来表示通过测试,也可以对其调用失败以使测试失败,或者可以超时并失败。

https://jestjs.io/docs/en/asynchronous.html

https://alligator.io/testing/asynchronous-testing-jest/

示例

注意,我将超时设置为1500ms

const myObservable = timer(0, 1000); // Example here

it('should fire', done => {
  myObservable.subscribe(data => {
    done();
  });
}, 1500); // Give 1500ms until it fails

使用 setTimeout

查看是否失败的另一种方法
const myObservable = timer(0, 1000); // Example here

it('should fire', done => {
  myObservable.subscribe(data => {
    done();
  });

  // Fail after 1500ms
  setTimeout(() => { done.fail(); }, 1500);
}, timeToFail);

答案 1 :(得分:4)

我在没有虚假计时器和超时的情况下测试 observable 的首选方法是 asyncawait 并在预期的转换承诺上使用 resolvesrejects

it('should do the job', async () => {
    await expect(myObservable
      .pipe(first())
      .toPromise())
      .resolves.toEqual(yourExpectation);
});

更新:

在 Rxjs 7 及以后的版本中,您可以使用 lastValueFromfirstValueFrom 进行 promise 转换

it('should do the job', async () => {
    await expect(lastValueFrom(myObservable))
      .resolves.toEqual(yourExpectation);
});

答案 2 :(得分:2)

测试任何 RXJS observable(Jest 或 no)的正确方法是在 TestScheduler 中使用 rxjs/testing

例如:

import { TestScheduler } from 'rxjs/testing';
import { throttleTime } from 'rxjs/operators';
 
const testScheduler = new TestScheduler((actual, expected) => {
  // asserting the two objects are equal - required
  // for TestScheduler assertions to work via your test framework
  // e.g. using chai.
  expect(actual).deep.equal(expected);
});
 
// This test runs synchronously.
it('generates the stream correctly', () => {
  testScheduler.run((helpers) => {
    const { cold, time, expectObservable, expectSubscriptions } = helpers;
    const e1 = cold(' -a--b--c---|');
    const e1subs = '  ^----------!';
    const t = time('   ---|       '); // t = 3
    const expected = '-a-----c---|';
 
    expectObservable(e1.pipe(throttleTime(t))).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });
});

来自RXJS marble testing testing docs

如果您有一个简单的 observable,尝试将 observable 等转换为 Promise 效果很好。一旦事情变得更加复杂,您就会在不使用大理石图和正确的测试库的情况下挣扎。

答案 3 :(得分:1)

从 6.2.1 版本开始,RxJS 支持 Jest 的假时间,因此您可以编写此测试的一种方法是:

const myObservable = timer(0, 1000);

jest.useFakeTimers('modern');

it('should fire', () => {
  myObservable.subscribe(data => {
    expect(data).toBe(0);
  });
  jest.runAllTimers();
});

我发布了有助于此类测试的 library(在下面的示例中,log 将日志记录添加到 observable,而 getMessages 检索已记录的消息) :

import { getMessages, log } from '1log';
import { timer } from 'rxjs';

const myObservable = timer(0, 1000);

test('timer', () => {
  myObservable.pipe(log).subscribe();
  jest.runAllTimers();
  expect(getMessages()).toMatchInlineSnapshot(`
    [create 1] +0ms [Observable]
    [create 1] [subscribe 1] +0ms [Subscriber]
    [create 1] [subscribe 1] [next] +1.000s 0
    [create 1] [subscribe 1] [complete] +0ms
    · [create 1] [subscribe 1] [unsubscribe] +0ms
  `);
});

答案 4 :(得分:0)

test('Test name', (done) => {
  service.getAsyncData().subscribe((asyncData)=>{
    expect(asyncData).toBeDefined();
       done();
    })
  });
})