【问题标题】:Unit test of custom snackbar with dismiss action带有解雇动作的自定义小吃店的单元测试
【发布时间】:2021-11-10 17:20:34
【问题描述】:

我已经定义了许多不同的方法来打开海关小吃店,有和没有持续时间,有和没有解雇事件,例如:

showError(title: string, message: string): void {
    this.zone.run(() => {
      this.snackBar.openFromComponent(NotificationSnackbarComponent, {
        duration: 3000,
        data: {
          title,
          message,
          snackType: 'error',
          closeSnackbar: () => {
            this.snackBar.dismiss();
          },
        },
      });
    });
  }

我怎样才能对这个事件进行单元测试:

closeSnackbar: () => {   this.snackBar.dismiss(); },

我尝试过这种方法:

it('should show notification smackbar from showError', () => {
    const spy = spyOn(snackBar, 'openFromComponent');
    const snackBarSpy = spyOn(snackBar, 'dismiss');
    service.showError('Title', 'Message');
    expect(spy).toHaveBeenCalled();
    snackBar.dismiss();
    expect(snackBarSpy).toHaveBeenCalled()
  });

但我需要测试closeSnackbar 而不是dismiss。我不知道如何才能访问该方法。我在每个配置之前都有这个:

let service: NotificationService;
let snackBar: MatSnackBar;

beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        MatSnackBarModule
      ],
      providers: [
        { provide: MatSnackBarRef, useValue: {} },
        { provide: MAT_SNACK_BAR_DATA, useValue: {} },
      ]
    });
    service = TestBed.inject(NotificationService);
    snackBar = TestBed.inject(MatSnackBar);
});

有什么想法吗?谢谢。

【问题讨论】:

    标签: angular unit-testing jasmine karma-jasmine


    【解决方案1】:

    试试下面的方法,我添加了 cmets。希望你能跟随并理解。

    let service: NotificationService;
      let snackBar: MatSnackBar;
      let mockSnackBarRef: jasmine.SpyObj<MatSnackBarRef>;
    
      beforeEach(() => {
        // the first string ('SnackBarRef') is used for debugging purposes
        // the second array of strings are public methods you would like to mock
        mockSnackBarRef = jasmine.createSpyObj<MatSnackBarRef>('SnackBarRef', ['openFromComponent', 'dismiss']);
        TestBed.configureTestingModule({
          imports: [
            MatSnackBarModule
          ],
          providers: [
            // change it to provide the mock - I assume this.snackBar is
            // MatSnackBarRef
            { provide: MatSnackBarRef, useValue: mockSnackBarRef },
            { provide: MAT_SNACK_BAR_DATA, useValue: {} },
          ]
        });
        service = TestBed.inject(NotificationService);
        snackBar = TestBed.inject(MatSnackBar);
      });
    
    ....
    it('should show notification smackbar from showError', () => {
        service.showError('Title', 'Message');
        // expect method to be called
        expect(mockSnackBarRef.openFromComponent).toHaveBeenCalled();
        // get the 2nd argument of the most recent call of openFromComponent
        const secondArgument = mockSnackBarRef.openFromComponent.calls.mostRecent().args[1];
        // call the closeSnackbar
        secondArgument.data.closeSnackbar();
        // expect the dismiss to be called
        expect(mockSnackBarRef.dismiss).toHaveBeenCalled();
      });
    

    【讨论】:

    • 您好,感谢您的回复。我在您的示例中遇到此错误: Generic type 'MatSnackBarRef' requires 1 type argument(s) 我不太清楚模拟是如何工作的。知道什么是必要的吗?
    • 如果我添加我的snackbar自定义组件(如果我是understabdibng),比如: let mockSnackBarRef: jasmine.SpyObj;我在 mockSnackBarRef 上有一个错误,例如: let mockSnackBarRef: jasmine.SpyObj;也许我做错了什么
    • 看来MatSnackBarRef 接受了一个泛型(T),我认为T 类型的泛型描述了openFromComponentdata 的形状。尝试将MatSnackBarRef&lt;any&gt; 放在任何需要的地方。 any 表示它可以是任何东西 object, array, string, number, boolean, custom data type
    • 那么this.snackbar 是什么?它是对 HTML 中的快餐栏组件的引用吗?如果它是 html 中的一个组件,并且您收到 cannot read property openFromComponent` of undefined`,则很可能意味着该组件当时没有在 HTML 中绘制。它可以被 *ngIf 或类似的东西阻止。
    • 所以也许是一个时间问题?好的,让我看看我是否抓住了可能性。谢谢
    猜你喜欢
    • 2016-02-03
    • 2020-11-27
    • 2019-10-14
    • 2020-01-14
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多