如何测试所有订阅都在Angular中取消订阅?

时间:2019-02-08 08:24:55

标签: angular testing rxjs

基本上,我想检查ngOnDestroy调用后是否有任何活动的订阅。现在,该代码将收集组件属性数组中的所有订阅,并取消订阅ngOnDestroy。我很容易忘记为该数组添加一个新创建的订阅。想要编写一个测试来帮助我消除这种情况。

3 个答案:

答案 0 :(得分:1)

不确定是否要尝试测试ngOnDestroy方法是否终止了在公共可观察对象外部启动的订阅,或者是否要尝试查看组件内部是否还有任何杂散的内部订阅。

对于前者,您可以编写如下测试:

  it('should end subscriptions when the component is destroyed', () => {
    // Setup the spies
    const spy = jasmine.createSpy();
    const noop = () => {};

    // Start the subscriptions
    const streams = [component.streamOne$, component.streamTwo$, component.streamThree$];
    streams.forEach(stream => stream.subscribe(noop, noop, spy));

    // Destroy the component
    component.ngOnDestroy();

    // Verify the spy was called three times (once for each subscription)
    expect(spy).toHaveBeenCalledTimes(streams.length);
  });

这将确保ngOnDestroy能够完成应做的工作,并终止在此组件的公共可观察对象上启动的所有订阅。

但是,如果您关心的是后者,那么检查流失订阅的唯一方法是通过在rxjs中猴子修补Observable。 This library does it well(我没有隶属关系)。用它编写测试很简单:

import { setup, track, printSubscribers } from 'observable-profiler';

describe('MyComponent', () => {
  beforeAll(() => {
    setup(Observable);
  });

  it('should not have any stray subscriptions', () => {
    track();

    const fixture = TestBed.createComponent(MyComponent);
    fixture.detectChanges();
    fixture.destroy()

    const subscriptions = track(false);
    expect(subscriptions).toBeUndefined();
  });
  ...

答案 1 :(得分:0)

您可以做一个简单的技巧,在每个订阅中增加服务的价值,在每个取消订阅中减少服务的价值,然后检查如果该值为0,那么没有订阅有效

mysubscription.subscribe( data => { this.myService.myValue++;})
mysubscription.unsubscribe( data => { this.myService.myValue--;})

答案 2 :(得分:0)

您可以使用takeUntil()运算符来代替向数组添加订阅。

这样,您创建了一个Subject,它将在ngOnDestroy上产生价值,并一次取消订阅多个订阅

 unsubscribeSignal: Subject<void> = new Subject();

 ngOnInit() {

    firstSubscription = firstObservable
    .pipe(
       takeUntil(this.unsubscribeSignal.asObservable()),
    )
    .subscribe(result => {});

    secondSubscription = secondObservable
    .pipe(
       takeUntil(this.unsubscribeSignal.asObservable()),
    )
    .subscribe(result => {});

    thirdSubscription = thirdObservable
    .pipe(
       takeUntil(this.unsubscribeSignal.asObservable()),
    )
    .subscribe(result => {});

  }

  ngOnDestroy(){
    this.unsubscribeSignal.next();
    // Don't forget to unsubscribe from subject itself
    this.unsubscribeSignal.unsubscribe();
  }