用玩笑测试 Observables

问题描述 投票:0回答:6

如何使用 Jest 测试 Observables?

我有一个每秒都会触发的 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 一起使用。

rxjs observable jestjs
6个回答
35
投票

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);

26
投票

在没有假定时器和超时的情况下测试简单可观察量的首选方法是

async
await
并在预期转换的 Promise 上使用 resolvesrejects

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

在 Rxjs 7 及更高版本中,您可以使用 lastValueFromfirstValueFrom 进行 Promise 转换。

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

对于更复杂的场景,请检查另一个有洞察力的答案


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

8
投票

测试任何 RXJS 可观察值的正确方法(开玩笑或不)是使用

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大理石测试测试文档

如果您有一个简单的可观察量,尝试将可观察量等转换为承诺会很好。一旦事情变得更加复杂,如果不使用弹珠图和正确的测试库,您就会陷入困境。


1
投票

这是使用

fakeAsync

的 Angular 方法

假设我们有一个 FooService ,其中有一个 Observable

closed$
,每次我们调用服务的
dismiss()
方法时都会发出。

@Injectable()
export class FooService {
    private closeSubject$ = new Subject<void>();
    public close$ = this.closeSubject$.asObservable();
    
    public dismiss() {
        this.closeSubject$.next();
    }
}

然后我们可以像这样测试

close$
发射

describe('FooService', () => {
    let fooService: FooService;

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [FooService]
        });
        fooService= TestBed.inject(FooService);
    });

    it('should emit a close event upon calling dismiss()', fakeAsync(() => {
        const callbackSpy = jest.fn();
        fooService.close$.subscribe(() => {
            callbackSpy();
        });
        fooService.dismiss();
        tick();
        expect(callbackSpy).toHaveBeenCalledTimes(1);
    }));
});

0
投票

有上面提到的2种方法

  1. 在我们的测试中获取参数并在测试后调用它。
  2. 使用firstValueFrom(myObs) 或lastValueFrom(myObs) 将我们的observable 转换为promise。并与他们一起使用异步等待...

如果我们有多个可观察值要测试,那么我们必须在测试中嵌套可观察值,因为我们只能调用一次 done() 。在这种情况下,异步等待方法会派上用场。 在此示例中,当我们调用过滤器 Customer 时,所有三个可观察量都会发出值,因此我们必须测试所有这些值。

it('Filter Customers based on Producers- Valid Case Promise way ', async () => {
  service.filterCustomers('Producer-1');

  await expect(firstValueFrom(service.customers$)).resolves.toEqual(['Customer-1']);

  await firstValueFrom(service.customers$).then((customers: string[]) => {
    expect(customers).toEqual(['Customer-1']);
    expect(customers.length).toBe(1);
  });

  await expect(firstValueFrom(service.products$)).resolves.toEqual([]);
  await expect(firstValueFrom(service.types$)).resolves.toEqual([]);
});
© www.soinside.com 2019 - 2024. All rights reserved.