【问题标题】:How to test a function with a Subscription that returns void如何使用返回 void 的订阅测试函数
【发布时间】:2019-03-07 08:05:30
【问题描述】:

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

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

我有一个 TypeScript EditComponent 和一个 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 的理解是它是同步运行的,所以我认为这会起作用。

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

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

有什么更好的方法来测试这个组件功能?

【问题讨论】:

    标签: angular typescript jasmine rxjs


    【解决方案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 并且无法读取属性“订阅”。在这种情况下,我通常通过创建新的 Observable 或使用 of() 来存根其结果并返回该组件可能需要与之交互的值。

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

    【讨论】:

    • 谢谢!这非常有效并且非常有意义。如果我向TestBed 添加一个新的提供者,比如{ provide: Router, useValue: jasmine.createSpyObj('Router', { navigate: of([/models/details/${model.id}]) }) },,你知道是否有办法添加一个expect(router.navigate).toHaveBeenCalled();(或类似的)测试?
    • 不客气!只需将 Jasmine 创建的 spy obj 分配给一个变量,然后您就可以expect 他们。像这样let router = jasmine.createSpyObj('Router', { navigate: of([/models/details/${model.id}]) }) 然后expect(router.navigate).toHaveBeenCalled()。基本上,expect() 需要可以从spyOn 到对象的该函数的间谍函数,或者使用间谍函数(createSpyObj() 所做的)然后传入间谍函数。 Here 是处理测试路由组件的官方指南。
    猜你喜欢
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 2020-06-22
    • 2022-06-27
    • 2021-12-09
    相关资源
    最近更新 更多