【问题标题】:Explanation why testing with Subject RXJS fails and with BehaviourSubject succeeds解释为什么使用 Subject RXJS 测试失败而使用 BehaviourSubject 测试成功
【发布时间】:2020-09-16 14:21:51
【问题描述】:

在这个 Angular 应用程序中,我想在尝试登录之前等待加载一些数据。

一开始我是用Subject 实现的,像这样:

private _requiredDataLoadedSubject$: Subject<boolean> = new Subject();
private get _requiredDataLoaded$(): Observable<boolean> {
    return this._requiredDataLoadedSubject$.pipe(
    shareReplay({ refCount: true, bufferSize: 1 })
    );
}

像这样使用它:


  private _loadRequiredData(): void {
      this.integrationService.loadData$().subscribe(data => {
          this._requiredDataLoadedSubject$.next(true);
      })
  }

  login(): Observable<boolean> {
    this._loadRequiredData();
    return this._requiredDataLoaded$.pipe(
      switchMap(() => integrationService.realLogin();
      )
    )
  }

上菜时它可以工作,但是在测试时,我无法通过测试。测试到达登录时主题为undefined

Subject 实现更改为BehaviorSubject(保持状态),测试通过。

private _requiredDataLoadedSubject$: BehaviorSubject<boolean> = new BehaviorSubject(false);
private get _requiredDataLoaded$(): Observable<boolean> {
    return this._requiredDataLoadedSubject$.pipe(
    filter(value => !!value),
    shareReplay({ refCount: true, bufferSize: 1 })
    );
}

在测试中我做了这样的事情:

describe("WHEN: login", () => {
  const CHAT_MOCK = CHATS_RESPONSE_MOCK[0];
  let workgroupsloaded;
  beforeEach(() => {
    spyOn(integrationService, "loadData$").and.returnValue(of(DATA_MOCK));
    spyOn(integrationService, "realLogin").and.callThrough();
    service.login().pipe(take(1)).subscribe();
  });

  it("THEN: should call integrationService.realLogin", () => {
    expect(integrationService.realLogin).toHaveBeenCalled();
  });
});

如果有人能解释为什么会发生这种情况,那就太好了!谢谢! :)

更新

我了解SubjectBehaviorSubject 之间的区别。我不明白的是为什么 Subject 实现在测试中不起作用。

我会解释的。由于执行管道的工作方式,在Subject 实现中:

  • login()引用this._requiredDataLoaded$时,主题还没有初始化,所以会等到数据到来。
  • integrationService.loadData$返回值时,更新主题。
  • 当主题更新时,可观察的 _requiredDataLoaded$ 管道其新数据。
  • 当 observable _requiredDataLoaded$ 返回数据时,login 应该调用 integrationService.realLogin

【问题讨论】:

  • 提示:filter(value =&gt; !!value)

标签: angular typescript unit-testing rxjs jestjs


【解决方案1】:

当您使用Subject.next 发出时,由于没有完成订阅,因此值为“丢失”。

BehaviourSubject 的区别在于,每当有新订阅到达时,都会重新发出最新发出的值。这就是代码有效的原因。

【讨论】:

  • 您知道为什么在为应用程序提供服务时会这样吗?我明白你的意思,但我觉得奇怪的是它只在测试中失败
  • 哼..我又读了一遍这个问题。您说错误是您调用登录时未定义主题?喜欢你cannot call pipe from from undefined?此外,当您从 Subject 更改为 BehaviourSubject 时,您还会在其中包含一个过滤器,对吗?
  • 是的,所以 BehaviourSubject 只发出真值。
猜你喜欢
  • 1970-01-01
  • 2018-09-26
  • 1970-01-01
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多