如何使用Jasmine测试AngularJS上的数据轮询?

时间:2017-04-07 10:08:29

标签: angularjs jasmine

我无法在控制器中测试数据轮询

控制器逻辑看起来像这样

$onInit() {
  this.requestRootLocations();
  this.startDataPolling();
}

private startDataPolling() {

  this.stop = this.$interval(() =>
    this.requestRootLocations()
    , this.DATA_POLLING_INTERVAL);
}

private requestRootLocations() {
      this.locationsService.requestRootElements().then(function (locationItem) {
        ...

        this.entityList = (locationItem["locations"] instanceof Array) ? locationItem["locations"] : [];
      }.bind(this), function () {
        console.log("Error on loading locations data.");
      });
    }

更新 服务中的http请求:

public requestRootElements() {
      return this.$http.get(this.API + "locations").then((response) => response.data);
    }

这样可以正常工作。

测试用例看起来像这样

it("should call http request on intervals", function () {

  ctrl.$onInit();
  $httpBackend.whenGET(api + "locations").respond(200, locationData);

  // advance in time by 1 seconds
  $interval.flush(1000);

  $httpBackend.expectGET(api + "locations");
  // after 1 seconds locations should be called once
  $httpBackend.flush();

  expect(ctrl.counts.length).toBe(4);
  expect(ctrl.entities.length).toBe(6);

  $interval.flush(dataPollingInterval);
  $httpBackend.expectGET(api + "locations"); //does not work, why?
  $httpBackend.flush();

  // after the second call the data should be the same in this case
  expect(ctrl.counts.length).toBe(4);
  expect(ctrl.entities.length).toBe(6);
});

但是在第二个期望的GET是一个错误

  

错误:请求不满意:GET / apiv1 / locations

1 个答案:

答案 0 :(得分:0)

这里的问题是单位不是孤立的。这是集成测试(控制器+服务+ $间隔),而不是单元测试。当测试变为红色时,无法确定哪个单元出现故障。

对此进行单元测试的正确策略是模拟除测试单元(控制器)之外的所有内容。 $interval也可以选择性地进行模拟,我们并不需要测试它是如何工作的 - 这已经被Angular测试了。

constructor(...) {
  ...
  // bind callback method
  this.dataPollingHandler = this.dataPollingHandler.bind(this);
}

$onInit() {
  this.requestRootLocations();
  this.stop = this.$interval(this.dataPollingHandler, this.DATA_POLLING_INTERVAL);
}

private dataPollingHandler() {
  this.requestRootLocations()
}

它可以像

一样进行测试
spyOn(ctrl, 'requestRootLocations');

// unbind callback method
ctrl.dataPollingHandler.call(null);

expect(ctrl.requestRootLocations).toHaveBeenCalled();

...

var intervalPromise = $q.resolve();
var intervalMock = jasmine.createSpy().and.returnValue(intervalPromise);
var ctrl = $controller(..., { $interval: intervalMock });

ctrl.$onInit();
expect(ctrl.stop).toBe(intervalPromise);
expect($intervalStub).toHaveBeenCalledWith(ctrl.dataPollingHandler, 1000);

...

var locationsServiceMock = {
  requestRootLocations: jasmine.createSpy().and.returnValue($q.resolve(locationData));
}

var ctrl = $controller(..., { locationsService: locationsServiceMock });
// now ctrl.requestRootLocations can be tested
...

可以在套件中进行单元测试和集成测试,但是当存在适当的控制器和服务单元测试时,集成测试就变得多余了。