如何使用返回空值的订阅测试功能

时间:2018-10-02 08:00:28

标签: angular typescript jasmine rxjs

我有一个带ModelService函数的TypeScript edit

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函数的最佳方法是什么?

我有一个执行此操作的茉莉花测试:

// 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的理解是,它可以同步运行,所以我认为这可以工作。

我还尝试使用asynctick()done()的多种变体,但是在调用组件的变量时,它们给出的消息相同或失败,并且Cannot read property 'subscribe' of undefined失败edit功能。

在其他测试中,我已经可以使用return fixture.whenStable().then()并且可以正常工作(如here所述),但是由于组件函数返回了{{ 1}},而不是Promise。

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

1 个答案:

答案 0 :(得分:1)

对于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并且不能被读取为属性'subscribe'。在这种情况下,我通常通过创建新的Observable或使用of()来存根其结果,并返回此组件可能需要与之交互的值。

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