如何测试NgRx Effect中的forkJoin?测试未达预期求助
解决NgRx Effect中forkJoin的测试问题
你的测试没触发forkJoin之后的逻辑,核心问题出在cold Observable的定义上——forkJoin要求所有内部Observable都完成后,才会发射合并结果,而你当前用的cold('-a', { a: null})没有标记完成,导致forkJoin一直处于等待状态,永远不会进入后续的switchMap。
修复步骤
1. 给Mock的Observable添加完成信号
把cold('-a', { a: null})改成cold('-a|', { a: null }),这里的|代表Observable完成。这样每个被Spy的requestVacationDay返回的Observable会正常结束,forkJoin就能收集所有结果并继续执行。
2. 用TestScheduler做更严谨的大理石测试
直接在subscribe里断言容易因异步时序问题导致不稳定,推荐用NgRx官方推荐的TestScheduler来验证Effect的输出:
import { TestScheduler } from 'rxjs/testing'; fit('should request several vacation days', () => { const testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); testScheduler.run(({ cold, expectObservable }) => { // 模拟触发的Action const triggerAction = vacationActions.RequestVacationDays({ requestedDays: ['2020-09-25', '2020-09-26'] }); actions$ = cold('-a', { a: triggerAction }); // 模拟服务返回的Observable(带完成信号) const vacationServiceSpy = spyOn(vacationService, 'requestVacationDay') .and.returnValue(cold('-a|', { a: null })); // 预期的输出Actions:两个Action会依次发射 const expectedActions = cold('--(bc)', { b: ModalActions.OpenModal({ header: 'Requested vacations', message: 'All vacations has been requested correctly.' }), c: VacationsActions.GetUserVacations() }); // 验证Effect的输出是否符合预期 expectObservable(effects.requestVacationDays$).toBe(expectedActions); // 验证服务被调用两次 expect(vacationServiceSpy).toHaveBeenCalledTimes(2); }); });
为什么之前的测试不工作?
forkJoin的核心特性:只有当所有传入的Observable都完成时,才会发出一次合并结果。如果任何一个Observable未完成,forkJoin会一直等待,永远不会触发后续操作。- 你之前的
cold('-a', {a:null})只定义了发射值,但没有完成信号,所以每个Mock的请求Observable一直处于活跃状态,forkJoin无法完成。
额外注意点
- 确保你的Effect在TestBed中正确配置,
actions$是可观察的输入源。 - 如果
requestVacationDay服务方法本身返回的是会自动完成的Observable(比如HttpClient的请求),Mock时必须模拟这个完成行为,否则测试与实际运行逻辑不一致。
内容的提问来源于stack exchange,提问作者dmance
相关产品推荐
相关产品推荐

