如何使用依赖项测试简单的Angular服务

时间:2020-10-18 20:20:17

标签: angular typescript unit-testing testing jasmine

我想了解如何使用Angular中创建的依赖项来测试服务。该服务只有一种方法可以打开Angular Material Snackbar,并且不返回任何内容。根据条件,有两种显示方式-成功或错误。该服务没有公共属性,所有操作均以其包含的唯一方法完成。该服务还具有一些依赖性。伪代码如下:

export class SnackbarService {

  constructor(private snackBar: MatSnackBar, private status: Status) { }

  openSnackBar(arg: string | Error):void {
    let prop1: string;
    let prop2: number;
    let prop3: string;

    if (arg instanceof Error) {
      prop1 = this.status.default;
      prop2 = 5000;
      prop3 = 'error';
    } else {
      prop1 = 'another status';
      prop2 = 6000;
      prop3 = 'success';
    }

    this.snackBar.open(prop1, 'x', {
      prop2,
      horizontalPosition: 'center',
      verticalPosition: 'top',
      prop3
    });

}

现在进行测试。我以为,测试上述服务是否将以另一种方式编写可能会更容易-将公共属性作为参数传递给两个方法而不是一个方法-一个解决if语句的方法和另一个实际上打开的方法小吃店。但是,让我们说代码看起来像上面。当方法不返回任何内容且没有公共属性时,可以实际测试什么?

describe('SnackbarService', () => {
  let service: SnackbarService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        MatSnackBarModule
      ],
      providers: [
        SnackbarService
      ]
    });
    service = TestBed.inject(SnackbarService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

我知道应该将依赖项导入到测试中,但是除了创建服务本身之外,不知道如何测试其他任何东西。感谢任何建设性的提示!

3 个答案:

答案 0 :(得分:1)

自从MatSnackBar被注入依赖项以来,您可以对其进行模拟,窥探其open方法,并验证传递给它的参数。

因此您的测试设置应如下所示:

const mockMatSnackBar = {
  open: () => {}
};

const mockStatus = {
  default: ''
};

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [
    ],
    providers: [
      SnackbarService,
      { provide: MatSnackBar, useValue: mockMatSnackBar }, // <--- use mock
      { provide: Status, useValue: mockStatus } // <--- use mock
    ]
  });
  service = TestBed.inject(SnackbarService);
  matSnackBar = TestBed.inject(MatSnackBar);
});

您的测试将如下所示:监视open方法并验证其调用的参数:

it('calls the MatSnackBar open method with status, "x", and a config object', () => {
  const matSnackBarSpy = spyOn(matSnackBar, 'open').and.stub();

  service.openSnackBar('arg');

  expect(matSnackBarSpy.calls.count()).toBe(1);

  const args = matSnackBarSpy.calls.argsFor(0);
  expect(args.length).toBe(3);
  expect(args[0]).toBe('another status');
  expect(args[1]).toBe('x');
  expect(args[2]).toEqual({
    prop2: 6000,
    horizontalPosition: 'center',
    verticalPosition: 'top',
    prop3: 'success'
  });
});

Here's a StackBlitz显示了这种方法。

答案 1 :(得分:0)

您可以验证它应该打开。

styles

答案 2 :(得分:0)

根据昨天的一些提示(其中一些已经消失),Jasmine docsthis post,我能够编写一些基本测试(注释和working StackBlitz中的描述)

describe("SnackbarService", () => {
  let service: SnackbarService;
  // mocking service
  const mockSnackbarService = jasmine.createSpyObj("SnackbarService", [
    "openSnackBar"
  ]);

  beforeEach(() => {
    TestBed.configureTestingModule({
      // providing the service and mock into the Testbed
      providers: [{ provide: SnackbarService, useValue: mockSnackbarService }]
    });
    // injecting the service
    service = TestBed.inject(SnackbarService);
  });

  it("should be created", () => {
    expect(service).toBeTruthy();
  });

  describe("openSnackBar", () => {
    it("should open the snack bar", () => {
      const arg = "test";
      // calling mock
      mockSnackbarService.openSnackBar.and.callThrough();
      // calling service method with argument
      service.openSnackBar(arg);
      // checking if method has been called
      expect(service.openSnackBar).toHaveBeenCalled();
    });
  });
});