NgRx Effect单元测试失败排查:预期值含hasValue:true但实际返回值缺失该字段
解决NgRx Effect单元测试中
--?(无值输出)的问题 你的测试失败核心原因是Effect中的withLatestFrom没有获取到预期的store数据流,导致整个流卡在了组合步骤,无法继续执行后续的service调用和action分发。
问题分析
你的Effect里用了withLatestFrom(this.addNewLedgerAccountStore$.select(...))来获取表单数据,这个操作符要求源流(action流)和内部流(store selector流)都至少发出过一次值,才会把两者的值组合起来传递给switchMap。但在你的测试代码中,只mock了service的返回,完全没有处理store selector的流——这就导致withLatestFrom一直等待store的流发出值,整个Effect流无法向下执行,最终输出--?(表示流没有发出预期的有效值)。
解决方案
你需要为addNewLedgerAccountStore$的select方法添加mock,让它返回一个包含mockedLedgerAccountForm的可观察流,确保withLatestFrom能拿到需要的表单数据。
修改后的测试代码示例
describe(`AddNewLedgerRequest$`, () => { it(`should dispatch AddNewLedgerAccountSuccess action if service succeeds`, () => { const action = new fromActions.AddNewLedgerAccountRequest(); actions$ = hot('-a', { a: action }); // 新增:mock store selector的返回流,确保发出表单数据 addNewLedgerAccountStore$.select(AddNewLedgerAccountSelectors.ledgerAccountFormSelector) .mockReturnValue(hot('-c', { c: mockedLedgerAccountForm })); const outcome = new fromActions.AddNewLedgerAccountSuccess({ ledgerAccount: mockedLedgerAccount }); const expected$ = cold('--b', { b: outcome }); const result$ = cold('-b', { b: mockedLedgerAccount }); addNewLedgerAccountSpy.mockReturnValue(result$); expect(effects.addNewLedgerAccountRequest$).toBeObservable(expected$); expect(addNewLedgerAccountSpy).toHaveBeenCalledWith(mockedLedgerAccountForm); }); });
额外说明
- 时间线匹配:这里我们把store的流设为
-c(10ms时发出表单数据),和action流-a的时间点一致,这样withLatestFrom会在10ms时完成组合,然后调用service,service返回的-b会在20ms时发出结果,刚好匹配预期的--b(20ms时发出Success action)。 - 验证store调用:如果需要,你还可以添加断言来验证store的select方法是否被正确调用:
expect(addNewLedgerAccountStore$.select).toHaveBeenCalledWith(AddNewLedgerAccountSelectors.ledgerAccountFormSelector);
这样修改后,你的Effect就能正常走完整个流程,发出预期的AddNewLedgerAccountSuccess action,测试就能通过了。
内容的提问来源于stack exchange,提问作者Cluadia Hedda
相关产品推荐
相关产品推荐

