【问题标题】:Angular2 - Test a function that calls a http service insideAngular2 - 测试一个调用内部http服务的函数
【发布时间】:2018-01-10 04:10:25
【问题描述】:

我目前正在尝试测试一个调用 http 请求服务的函数,然后在订阅部分执行某些操作(调用一个函数并设置一个变量)。到目前为止,我的方法是只调用该函数,我认为请求服务将被自动调用,因此订阅部分将被执行。但是,我觉得这不是这样做的方式,因为它不起作用。

我要测试的功能:

  public trainBot() {
    this.isTraining = true;
    this.requestsService.trainModel(this.botId, false)
      .subscribe(response => {
        this.trainingStatus = this.trainingStatusMapping[response['status']];
        this.pollTrainingStatus();
      });
  }

到目前为止我的测试(不起作用)。

it('should poll the training status', () => {
    spyOn(component, 'pollTrainingStatus').and.callThrough();
    component.trainBot();
    fixture.detectChanges();
    expect(component.pollTrainingStatus).toHaveBeenCalled();
  });

那么,谁能告诉我如何在 .subscribe(... 部分中测试该部分?

更新:

正如有人建议的那样,我在测试中添加了 returnValue 和 async。他们仍然不工作,但现在看起来像这样:

it('should poll the training status', fakeAsync(() => {
    component.trainBot();
    spyOn(service, 'trainModel').and.returnValue(Observable.of({'status': 'training'}));
    spyOn(component, 'pollTrainingStatus').and.callThrough();
    fixture.detectChanges();
    tick(1);
    expect(service.trainModel).toHaveBeenCalled();
    expect(component.pollTrainingStatus).toHaveBeenCalled();
  }));

错误是一样的

【问题讨论】:

  • 您能否分享您收到的错误或失败测试的输出?
  • @Kevin “预计间谍 pollTrainingStatus 已被调用。”这意味着 pollTrainingStatus() 没有被调用
  • 看看这个问题:angular2 testing using jasmine for subscribe method。让我知道那里的答案是否适合您。
  • 所以我尝试添加 '.and.returnValue({ subscribe: () => {} })' 部分,但这并没有改变任何东西
  • 我刚刚意识到,你不需要监视this.requestsService.trainModel吗?

标签: angular unit-testing typescript


【解决方案1】:

传递给subscribe() 的函数被异步调用。这意味着您的断言在调用 this.pollTrainingStatus() 之前运行。您需要使用async() or fakeAsync() utility function

在代码中可以是这样的(如果使用fakeAsync()):

import { fakeAsync } from '@angular/core/testing';

it('should poll the training status', fakeAsync(() => {
  ...
  expect(component.pollTrainingStatus).toHaveBeenCalled();
}));

【讨论】:

  • 你有没有像docs一样添加tick()
【解决方案2】:

首先,您需要在运行 trainBot() 方法之前创建您的间谍。这应该可以解决您的测试问题。

it('should poll the training status', () => {
  spyOn(service, 'trainModel').and.returnValue(Observable.of({'status': 'training'}));
  spyOn(component, 'pollTrainingStatus');

  component.trainBot();

  expect(service.trainModel).toHaveBeenCalled();
  expect(component.pollTrainingStatus).toHaveBeenCalled();
}));

不过,让我们谈谈您的测试策略。

说实话,您是在测试一个组件,而不是服务,因此您不应该让服务方法调用。

spyOn(service, 'trainModel').and.returnValue(Observable.of({'status': 'training'}));

此外,单元测试应该测试尽可能小的东西。您实际上是在这里测试回调,回调可能应该是命名方法而不是匿名箭头函数。然后您可以在其他测试中测试和验证回调的功能。

public trainBot() {
  this.isTraining = true;
  this.requestsService.trainModel(this.botId, false)
      .subscribe(response => this.onTrainbotSuccess(response));
}

public onTrainbotSuccess(response) {
  this.trainingStatus = this.trainingStatusMapping[response['status']];
  this.pollTrainingStatus();
}

this 测试中,您可以测试响应方法是否被调用

it('should call service.trainModel', () => {
  spyOn(service, 'trainModel').and.returnValue(Observable.of({'status': 'training'}));

  component.trainBot();

  expect(service.trainModel).toHaveBeenCalled();
});

it('should send success responses to onTrainbotSuccess()', () => {
  spyOn(component, 'onTrainbotSuccess');
  spyOn(service, 'trainModel').and.returnValue(Observable.of({'status': 'training'}));

  component.trainBot();

  expect(component.onTrainbotSuccess).toHaveBeenCalled();
});

现在我们可以专门针对成功回调的作用编写测试。

it('should poll the training status', () => {
  spyOn(component, 'pollTrainingStatus');

  component.onTrainbotSuccess({'status': 'training'});

  expect(component.pollTrainingStatus).toHaveBeenCalled();
});

【讨论】:

  • 我遇到了同样的情况,但在调用 component.pollTrainingStatus 时它失败了。预期的 spy pollTrainingStatus 已被调用。
  • 我喜欢你分解代码的方式。但是我不禁注意到引入了一个新的公共方法 onTrainbotSuccess 尽管使测试成为可能。这不是有点骇人听闻吗? Jasmine 也可以监视私有方法,还是您为了测试而破坏了封装?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
相关资源
最近更新 更多