如何为带关闭操作的自定义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兼容:
- 修改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注入 });
- 把测试中
service.showError的调用放到ngZone.run中执行
ngZone.run(() => { service.showError('Title', 'Message'); });
内容的提问来源于stack exchange,提问作者CVO
相关产品推荐
相关产品推荐

