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

如何为带关闭操作的自定义snackbar编写closeSnackbar单元测试

实现思路

你要测试closeSnackbar回调,核心是从snackBar.openFromComponent的调用参数中取出传入的配置对象,拿到挂载在data下的closeSnackbar方法,主动调用该方法后验证dismiss逻辑是否生效即可。

具体步骤

  • 第一步:在调用service.showError之后,从openFromComponent的spy调用记录里取出配置参数
  • 第二步:从配置参数的data字段中拿到closeSnackbar回调函数
  • 第三步:主动执行这个回调函数,验证snackBar.dismiss是否被调用

你原来的测试用例存在逻辑问题:直接手动调用snackBar.dismiss()触发spy,完全没有验证closeSnackbar回调本身的逻辑,属于无效测试。修正后的完整测试用例如下:

it('should trigger dismiss when closeSnackbar callback is called', () => {
  // 监听openFromComponent和dismiss方法
  const openSpy = spyOn(snackBar, 'openFromComponent');
  const dismissSpy = spyOn(snackBar, 'dismiss');

  // 调用showError方法触发snackbar打开
  service.showError('Title', 'Message');
  expect(openSpy).toHaveBeenCalled();

  // 从openFromComponent的调用参数中拿到配置对象
  const openConfig = openSpy.calls.mostRecent().args[1];
  // 取出closeSnackbar回调
  const closeSnackbar = openConfig.data.closeSnackbar;
  // 主动调用回调
  closeSnackbar();

  // 验证dismiss被回调触发
  expect(dismissSpy).toHaveBeenCalled();
});

可选兼容处理

如果执行测试时发现openSpy未被调用,是因为showError里的逻辑包裹了zone.run,可以在测试中注入NgZone兼容:

  1. 修改beforeEach配置,新增NgZone注入
let service: NotificationService;
let snackBar: MatSnackBar;
let ngZone: NgZone; // 新增NgZone声明

beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        MatSnackBarModule
      ],
      providers: [
        { provide: MatSnackBarRef, useValue: {} },
        { provide: MAT_SNACK_BAR_DATA, useValue: {} },
      ]
    });
    service = TestBed.inject(NotificationService);
    snackBar = TestBed.inject(MatSnackBar);
    ngZone = TestBed.inject(NgZone); // 新增NgZone注入
});
  1. 把测试中service.showError的调用放到ngZone.run中执行
ngZone.run(() => {
  service.showError('Title', 'Message');
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 17:06:04