【发布时间】: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();
});
});
如果有人能解释为什么会发生这种情况,那就太好了!谢谢! :)
更新
我了解Subject 和BehaviorSubject 之间的区别。我不明白的是为什么 Subject 实现在测试中不起作用。
我会解释的。由于执行管道的工作方式,在Subject 实现中:
- 当login()引用
this._requiredDataLoaded$时,主题还没有初始化,所以会等到数据到来。 - 当integrationService.loadData$返回值时,更新主题。
- 当主题更新时,可观察的 _requiredDataLoaded$ 管道其新数据。
- 当 observable _requiredDataLoaded$ 返回数据时,login 应该调用 integrationService.realLogin
【问题讨论】:
-
提示:
filter(value => !!value)
标签: angular typescript unit-testing rxjs jestjs