You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对NgRx Effects中withLatestFrom操作符进行单元测试

解决NgRx Effect单元测试的"You provided 'undefined' where a stream was expected."错误

看起来你的测试里有几个关键问题导致了这个错误,我来帮你逐个梳理并修正:

1. 服务方法返回值不是Observable

你的boardService.getBoardsFromParams被mock成直接返回普通对象successfulSignalRResult,但在实际Effect代码中,这个方法应该返回一个Observable(因为你调用了.pipe()操作符)。RxJS的操作符需要处理流,所以必须让mock方法返回Observable:

boardSvc.getBoardsFromParams = jest.fn(() => of(successfulSignalRResult));

2. Store选择器的Mock方式问题

你当前的store.select mock虽然返回了Observable,但需要确保它匹配你在Effect中使用的选择器fromRoot.getRouterState。另外,NgRx的store.select通常是通过选择器来调用的,最好明确mock对应选择器的返回:

// 方式1:mock指定的选择器
jest.spyOn(fromRoot, 'getRouterState').mockReturnValue(of(params));

// 方式2:如果直接mock store.select方法
store.select = jest.fn((selector) => {
  if (selector === fromRoot.getRouterState) {
    return of(params);
  }
  return of(null);
});

另外,你传入的params结构要和Effect中解构的一致,确保router.state.queryParams.boards能正确取到值(这里你传的是空对象,所以boards会是undefined,这没问题,但结构要对)。

3. Action类型不匹配

你的Effect中成功后返回的是backlogActions.GetBoardsSuccess(board),但测试里的预期结果是new backlogActions.GetAvailableBoardsSuccess([]),这两个action类型不匹配,会导致测试断言失败。要把预期的action改成和Effect中一致的类型:

const outcome = new backlogActions.GetBoardsSuccess([]);

4. toBeObservable的参数错误

你最后调用expect(effects.loadPlansOnParams$).toBeObservable({});,这里应该传入你定义的expected变量,而不是空对象:

expect(effects.loadPlansOnParams$).toBeObservable(expected);

修正后的完整测试代码

describe('getting boards from the params', () => {
  it('should return an empty array if no params', () => {
    const params = { state: { queryParams: {} } };
    const successfulSignalRResult = { isSuccessful: true, item: [] };
    const action = new backlogActions.GetBoardsInParams();
    // 修正:使用和Effect中一致的Success action
    const outcome = new backlogActions.GetBoardsSuccess([]);
    
    actions.stream = hot('-a', { a: action });
    
    // 修正:正确mock store.select返回对应选择器的Observable
    jest.spyOn(fromRoot, 'getRouterState').mockReturnValue(of(params));
    
    expected = cold('--b', { b: outcome });
    
    // 修正:让服务方法返回Observable
    boardSvc.getBoardsFromParams = jest.fn(() => of(successfulSignalRResult));
    
    // 修正:传入expected而不是空对象
    expect(effects.loadPlansOnParams$).toBeObservable(expected);
  });
});

另外,还要确保你在测试前正确初始化了Effects、Actions、Store和BoardService的mock实例,比如:

let effects: YourEffectsClass;
let actions: Actions;
let store: MockStore;
let boardSvc: jest.Mocked<BoardService>;

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      YourEffectsClass,
      { provide: Actions, useValue: new Actions(EMPTY) },
      { provide: BoardService, useValue: { getBoardsFromParams: jest.fn() } },
      provideMockStore(),
    ],
  });

  effects = TestBed.inject(YourEffectsClass);
  actions = TestBed.inject(Actions);
  store = TestBed.inject(MockStore);
  boardSvc = TestBed.inject(BoardService) as jest.Mocked<BoardService>;
});

这些修改应该能解决你遇到的"undefined stream"错误,同时让测试正确运行。

内容的提问来源于stack exchange,提问作者s.Lawrenz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:12:19