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

NgRx新手求助:如何测试带{dispatch: false}的Effect?

测试NgRx Effect中Service方法调用的解决方案

别担心,我来帮你搞定这个测试!针对你写的NotificationEffects,我们可以通过模拟依赖并触发对应Action,轻松验证notificationService.info是否被正确调用。下面是完整的测试代码和详细说明:

完整测试代码

import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { Observable, of } from 'rxjs';
import { NotificationEffects } from './notification.effects';
import * as notificationAction from './notification.actions';
import { NotificationService } from './notification.service';
import { cold } from 'jasmine-marbles';

describe('NotificationEffects', () => {
  let effects: NotificationEffects;
  let actions$: Observable<any>;
  let notificationServiceSpy: jasmine.SpyObj<NotificationService>;

  beforeEach(() => {
    // 创建NotificationService的模拟对象,监听info方法的调用
    const spy = jasmine.createSpyObj('NotificationService', ['info']);

    TestBed.configureTestingModule({
      providers: [
        NotificationEffects,
        // 提供可手动控制的Action流
        provideMockActions(() => actions$),
        // 用模拟对象替换真实的NotificationService
        { provide: NotificationService, useValue: spy }
      ]
    });

    effects = TestBed.inject(NotificationEffects);
    notificationServiceSpy = TestBed.inject(NotificationService) as jasmine.SpyObj<NotificationService>;
  });

  describe('notificationShow$', () => {
    it('should call notificationService.info with the payload config', () => {
      // 准备测试用的配置和Action
      const testConfig = { title: '测试通知', message: '这是一条测试消息' };
      const action = new notificationAction.NotificationShowAction({ config: testConfig });

      // 把Action注入到Effect的Action流中
      actions$ = of(action);

      // 订阅Effect(因为这个Effect是dispatch: false,订阅后才会执行内部的do逻辑)
      effects.notificationShow$.subscribe();

      // 验证info方法是否被正确调用,参数是否匹配
      expect(notificationServiceSpy.info).toHaveBeenCalledWith(testConfig);
    });

    // 如果你需要测试更复杂的流场景,可以用marbles测试方式
    it('should handle NOTIFICATION_SHOW action via marbles', () => {
      const testConfig = { title: '测试通知', message: '这是一条测试消息' };
      const action = new notificationAction.NotificationShowAction({ config: testConfig });
      // 用cold marble模拟异步Action流
      actions$ = cold('-a', { a: action });

      effects.notificationShow$.subscribe();

      expect(notificationServiceSpy.info).toHaveBeenCalledWith(testConfig);
    });
  });
});

关键步骤拆解

  • 模拟依赖:用jasmine.createSpyObj生成NotificationService的模拟对象,这样我们可以全程监听info方法的调用状态。
  • 配置测试环境:通过provideMockActions提供可手动控制的Action流,同时将模拟的Service注入测试模块,替换真实服务。
  • 触发Action:用of(action)或marbles的cold方法生成Action流,让Effect能接收到目标Action。
  • 执行Effect逻辑:因为你的Effect设置了dispatch: false(不输出新Action),所以需要手动订阅它,才能触发内部的do操作。
  • 验证调用结果:最后用Jasmine断言,检查info方法是否被调用,并且传入的参数和我们预设的一致。

为什么之前的示例没帮到你?

很多通用示例会重点讲解有输出Action的Effect测试,而你的Effect属于dispatch: false类型,不需要验证输出Action,只需要聚焦于Service方法的调用验证——这也是你可能没找到直接解决方案的原因。

内容的提问来源于stack exchange,提问作者camden_kid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:39:49