首页 > 解决方案 > 如何使用返回 void 的订阅测试函数

问题描述

我有一个ModelService带有edit函数的 TypeScript:

edit(model: Model): Observable<Model> {
  const body = JSON.stringify(model);
  return this.http.put(`/models/edit/${model.id}`, body));
}

我有一个带有订阅服务并在收到响应时导航EditComponent的函数的 TypeScript:edit

edit(model: Model): void {
  this.service
    .edit(model)
    .subscribe(() => this.router.navigate([`/models/details/${model.id}`]);
}

测试此组件edit功能的最佳方法是什么?

我有一个 Jasmine 测试可以做到这一点:

// Setup
TestBed.configureTestingModule({
  declarations: [EditComponent],
  providers: [
    {
      provide: ModelService,
      useValue: jasmine.createSpyObj('ModelService', ['edit'])
    }
  ]
});
const fixture = TestBed.createComponent(EditComponent);
const component = fixture.componentInstance;
const modelService = fixture.debugElement.injector.get(ModelService);
fixture.detectChanges();

// Test
it('should call edit', () => {
  fakeAsync(() => {
    component.edit(model);
    expect(modelService.edit).toHaveBeenCalled();
  });
});

但是通过这个测试,我总是SPEC HAS NO EXPECTATIONS在它运行时得到。我的理解fakeAsync是它同步运行,所以我认为这会起作用。

我也尝试过使用、 和的多种变体async,但在调用组件函数时,它们要么给出相同的消息,要么失败。tick()done()Cannot read property 'subscribe' of undefinededit

在其他测试中,我已经能够使用return fixture.whenStable().then()并且工作正常(如此处所述),但我不认为它在这里工作,因为组件函数正在返回void不是 Promise。

测试此组件功能的更好方法是什么?

标签: angulartypescriptjasminerxjs

解决方案


为了SPEC HAS NO EXPECTATIONS

这似乎不是正确的使用方式fakeAsync,这就是为什么它说没有期望。它应该是:

it('should call edit', fakeAsync(() => {
  component.edit(model);
  expect(modelService.edit).toHaveBeenCalled();
});

无论如何,modelService.edit()实际上是一个可以预期同步的调用,因为它是在内部调用的component.edit()

所以你可以像这样简单地测试它:

it('should call edit', () => {
  component.edit(model);
  expect(modelService.edit).toHaveBeenCalled();
});

为了Cannot read property 'subscribe' of undefined

因为您创建间谍对象而没有任何回报。因此,modalService.edit()返回undefined并且无法读取属性“订阅”。在这种情况下,我通常通过创建新的 Observable 或使用of()来存根其结果,并返回该组件可能需要与之交互的值。

jasmine.createSpyObj('ModelService', { edit: of() })

推荐阅读