Jest SpyOn在NgRx组件Store Effect中监听服务方法失效问题
测试NgRx组件Store的Effect方法
loadReviewByRouteId时断言失败的解决方法 我在测试NgRx组件Store的effect方法loadReviewByRouteId时遇到异常:运行测试时控制台输出了here!,说明getReviewById方法确实被执行了,但断言却失败,提示该方法调用次数为0。
相关Effect代码
readonly loadReviewByRouteId = this.effect( (): Observable<EmployeeReview> => this.route.params.pipe( switchMap(({id}) => this.reviewService.getReviewById(id)), tap((review) => this.setEmployeeReview(review)) ) )
测试配置
const mockReviewService = { getReviewById() { console.log('here!') } } TestBed.configureTestingModule({ imports: [RouterTestingModule.withRoutes([{path: '**', redirectTo: ''}])], providers: [ ReviewDetailsStore, { provide: ReviewService, useValue: mockReviewService }, { provide: ActivatedRoute, useValue: { params: of({id: 123}) } } ] })
测试用例
it('should call the review service with the route param id', () => { const getReviewServiceSpy = jest.spyOn(reviewService, 'getReviewById') reviewDetailsStore.loadReviewByRouteId() expect(getReviewServiceSpy).toHaveBeenCalled() })
错误信息
expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: called with 0 arguments
Number of calls: 0
解决方法
1. 确保Spy挂载到正确的实例
你当前的mockReviewService是字面量对象,jest.spyOn需要挂载到TestBed注入的实际服务实例上,而非原始mock对象。修改测试用例,从TestBed中获取服务实例后再挂载Spy:
it('should call the review service with the route param id', () => { const reviewService = TestBed.inject(ReviewService); const getReviewServiceSpy = jest.spyOn(reviewService, 'getReviewById'); reviewDetailsStore.loadReviewByRouteId(); expect(getReviewServiceSpy).toHaveBeenCalledWith(123); })
2. 处理Observable的异步特性
NgRx Component Store的Effect返回Observable,属于异步操作。若不等待异步流程完成,断言会在代码执行前触发。可以用Angular测试工具tick()结合async/await处理:
it('should call the review service with the route param id', async () => { const reviewService = TestBed.inject(ReviewService); const getReviewServiceSpy = jest.spyOn(reviewService, 'getReviewById') .mockReturnValue(of({} as EmployeeReview)); reviewDetailsStore.loadReviewByRouteId(); await tick(); // 触发所有异步操作 expect(getReviewServiceSpy).toHaveBeenCalledWith(123); })
3. 修复mock方法的返回值
原getReviewById方法未返回值,但Effect的switchMap期望它返回Observable,这会导致管道中断,影响异步流程。给mock方法添加Observable返回值:
const mockReviewService = { getReviewById(id: number) { console.log('here!') return of({} as EmployeeReview); // 返回模拟的EmployeeReview Observable } }
内容的提问来源于stack exchange,提问作者user3817370
相关产品推荐
相关产品推荐

