【问题标题】:Unit testing the service itself in Angular with SnackBar call使用 SnackBar 调用在 Angular 中对服务本身进行单元测试
【发布时间】:2020-05-12 15:53:25
【问题描述】:

我对 Angular Material 单元测试和服务单元测试都比较陌生。 我为我的应用程序创建了一个服务,我可以使用它调用 Material SnackBar 打开函数并传递一个消息参数。它在需要时在每个组件中都可以正常工作,但是对它的单元测试对我来说……很糟糕。

import { Injectable } from '@angular/core';
import { MatSnackBar, MatSnackBarRef, MatSnackBarConfig } from '@angular/material/snack-bar';

@Injectable({
  providedIn: 'root',
})
export class NotificationService {
  private snackBarConfig: MatSnackBarConfig;
  private snackBarRef: MatSnackBarRef<any>;
  private snackBarAutoHide = '5000';

  constructor(private sb: MatSnackBar) {}

  openSnackBar(message) {
    this.snackBarConfig = new MatSnackBarConfig();
    this.snackBarConfig.duration = parseInt(this.snackBarAutoHide, 0);
    this.sb.open(message, 'Dismiss', this.snackBarConfig);
  }
}

而所谓的测试规范文件是这样的:

import { Overlay } from '@angular/cdk/overlay';
import { TestBed } from '@angular/core/testing';
import { MatSnackBar } from '@angular/material/snack-bar';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { NotificationService } from './notification-service';

describe('NotificationService testing:', () => {
  let spectator: SpectatorService<NotificationService>;
  const createService = createServiceFactory({
    service: NotificationService,
    providers: [MatSnackBar, Overlay],
    entryComponents: [],
    mocks: [NotificationService],
  });

  beforeEach(() => (spectator = createService()));

  it('should openSnackBar() be known as function', () => {
    expect(typeof spectator.service.openSnackBar).toEqual('function');
  });

  it('should be created', () => {
    const dateService = spectator.inject(NotificationService);
    spyOn(spectator.service, 'openSnackBar');
    dateService.openSnackBar('Test');
    expect(spectator.service.openSnackBar).toHaveBeenCalledWith('Test');
  });
});

我的问题如下:

  1. 为什么我的因果报应说 openSnackBar(message) 方法不是 测试?我的意思是至少我测试它是否是一个函数。
  2. 我如何才能真正单独测试这样的服务?

提前谢谢你。

【问题讨论】:

    标签: angular unit-testing karma-jasmine angular9 spectator


    【解决方案1】:

    好的,我在朋友的帮助下解决了这个问题。 第一个问题是在我的构造函数中,我定义了一个私有的,而不是公共版本的 SnackBar (private sb: MatSnackBar -> public sb: MatSnackBar)。 其次,我稍微修改了测试文件,现在它看起来像这样并且工作正常:

    import { Overlay } from '@angular/cdk/overlay';
    import { TestBed } from '@angular/core/testing';
    import { MatSnackBar, MatSnackBarModule, MatSnackBarConfig } from '@angular/material/snack-bar';
    import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
    import { NotificationService } from './notification-service';
    
    describe('NotificationService testing:', () => {
      let spectator: SpectatorService<NotificationService>;
      let snackBar: MatSnackBar;
      let snackBarConfig: MatSnackBarConfig;
    
      const createService = createServiceFactory({
        service: NotificationService,
        imports: [MatSnackBarModule],
        providers: [MatSnackBarModule, Overlay],
        entryComponents: [],
        mocks: [NotificationService],
      });
    
      beforeEach(() => {
        TestBed.configureTestingModule({});
        snackBar = TestBed.inject(MatSnackBar);
        spectator = createService();
      });
    
      it('should service be created', () => {
        const service: NotificationService = TestBed.inject(NotificationService);
        expect(service).toBeTruthy();
      });
    
      it('should openSnackBar() be known as function', () => {
        expect(typeof spectator.service.openSnackBar).toEqual('function');
      });
    
      it(`should openSnackBar() call SnackBar's own open()`, () => {
        const service: NotificationService = TestBed.inject(NotificationService);
        snackBarConfig = new MatSnackBarConfig();
        snackBarConfig.duration = parseInt('5000', 0);
        const serviceSpy = spyOn(service, 'openSnackBar').and.callThrough();
        const snackSpy = spyOn(snackBar, 'open');
        expect(serviceSpy).not.toHaveBeenCalled();
        expect(snackSpy).not.toHaveBeenCalled();
        service.openSnackBar('Hello');
        expect(serviceSpy).toHaveBeenCalledWith('Hello');
        expect(snackSpy).toHaveBeenCalledWith('Hello', 'Dismiss', snackBarConfig);
      });
    });
    
    

    如果将来有人遇到同样的问题,希望对您有所帮助。我也确信,有一种更好、更好的方法可以做到这一点,但现在它正在工作并提供 100% 的覆盖率,这很重要。但会热忱欢迎日后对此提出修改建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-24
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 2020-06-26
      相关资源
      最近更新 更多