如何测试返回empty()的@ngrx/effects 4.1.1 Effect?
解决Ngrx Effects返回empty()的单元测试问题
我之前也踩过Ngrx Effects 4.x版本测试空Observable Effect的坑,结合你的代码和报错信息,给你梳理下问题原因和解决办法:
问题根源
你看到的报错是因为:
- 你的Effect没有明确设置
dispatch: false,Ngrx默认会期望这个Effect分发Action,但你返回的empty()是直接完成的Observable,没有任何Action输出,导致测试匹配失败。 - 即使你后来加了
dispatch: false,可能测试写法上还有小问题,没完全适配Ngrx 4.x的测试逻辑。
分步解决
1. 给Effect加上dispatch: false元数据
这是核心第一步!因为你的Effect只执行副作用(调用dialogsService.showDialog),不分发任何Action,必须显式告诉Ngrx这个配置:
@Effect({ dispatch: false }) // 加上这个配置! showDialog$: Observable<Action> = this .actions$ .ofType(ActionTypes.DIALOG_SHOW) .map((action: DialogAction) => action.payload) .switchMap(payload => { this.dialogsService.showDialog(payload.className); return empty(); });
2. 调整测试代码,兼顾副作用验证和空Observable匹配
测试这类Effect的重点应该是验证副作用是否执行,同时确认没有Action被分发。你可以这样修改测试:
describe('DialogEffects', () => { let effects: DialogEffects; let actions: Observable<any>; const mockDialogService = { showDialog: sinon.stub() }; beforeEach(() => { TestBed.configureTestingModule({ providers: [ DialogEffects, provideMockActions(() => actions), { provide: DialogsService, useValue: mockDialogService } ] }); effects = TestBed.get(DialogEffects); }); describe('showDialog$', () => { it('should call dialogService.showDialog and not dispatch any actions', () => { const dialogName = 'testDialog'; const action = showDialog(dialogName); // 模拟Action流 actions = hot('--a-', { a: action }); // 订阅Effect触发执行,验证服务方法调用 effects.showDialog$.subscribe({ complete: () => { expect(mockDialogService.showDialog.calledWith(dialogName)).toBe(true); } }); // 断言Effect返回空Observable(无任何Action输出) expect(effects.showDialog$).toBeObservable(empty()); }); }); });
如果你还是想用hot/cold的匹配方式,也可以这样写,同样能通过测试:
it('should return an empty observable and trigger showDialog', () => { const dialogName = 'testDialog'; const action = showDialog(dialogName); actions = hot('a', { a: action }); // cold('|')代表立即完成的空Observable,和empty()行为一致 const expected = cold('|'); expect(effects.showDialog$).toBeObservable(expected); // 重点:验证副作用执行 expect(mockDialogService.showDialog).toHaveBeenCalledWith(dialogName); });
关键提醒
- 在Ngrx 4.x中,
dispatch: false不是可选的,对于不输出Action的Effect必须设置,否则测试框架会一直期望有Action输出,导致匹配失败。 - 测试这类Effect时,不要只关注空Observable的匹配,更要验证核心的副作用逻辑(比如服务方法调用),这才是这个Effect的实际作用。
内容的提问来源于stack exchange,提问作者serlingpa
相关产品推荐
相关产品推荐

