使用$ httpBackend进行AngularJS测试 - 不调用Service

时间:2014-02-02 22:42:40

标签: javascript angularjs testing jasmine

我正在尝试测试非常简单的AngularJS Service加载JSON数据:

angular.module('archive', [])
  .factory('Loader', function ($http) {
    var result;
    $http.get('path').success(function(data) {
      result = data;
      console.log('returning: ', result);
    });
    return {
      getData: result
    }
  });

这是我的测试:

describe('TestArchive', function () {
  beforeEach(module('archive'));

  it('should load data', inject(function(Loader, $httpBackend){
    $httpBackend
      .whenGET('path')
      .respond(22);
    var result = Loader.getData;
    $httpBackend.flush();
    console.log(result);
  }));

});

我希望看到22加载,但正如我从console看到的那样,它不会发生,resultundefined。 知道什么是错的吗?

3 个答案:

答案 0 :(得分:1)

在服务定义中,您基本上是在说:

var result;
$http.get().success(function(data) {
    result = data; // will be executed after below 'return'
}
return result;

这意味着返回时结果将是未定义的,因为异步http调用。

更好的方法是返回一个返回实际结果的函数

return {
    getData: function() { return result; }
};

但要注意,即使在这种方法中,你也可能过早地调用getData()(在http请求有机会完成之前)。

最后,防止故障的方法是返回一个promise,手动创建(由@dimirc建议),或者简单地返回$ http.get()本身返回的promise:

return {
    getData: $http.get('path')
};

另外,请注意,response()喜欢将响应数据作为字符串,因为它也可以接受http状态(数字)作为第一个参数:

$httpBackend.whenGET('path').respond(200, '22');

它可能与一个数字一起作为单个参数,但最好明确说明你的意图:)

答案 1 :(得分:0)

您应该考虑来自.success的回调是异步调用的,因此我们可以使用promise来更好地处理结果。

angular.module('archive', [])
  .factory('Loader', function ($http, $q) {
    var result;
    var deferred = $q.defer();
    $http.get('path').success(function(data) {
      deferred.resolve(data);
      console.log('returning: ', data);
    });
    return {
      getData: deferred.promise
    }
  });

和测试

describe('TestArchive', function () {
  beforeEach(module('archive'));

  it('should load data', inject(function(Loader, $httpBackend){
    $httpBackend
      .whenGET('path')
      .respond(22);
    var promise = Loader.getData;
    promise.then(function(result){
      console.log(result);
    })
    $httpBackend.flush();
  }));

});

答案 2 :(得分:0)

警告:我真的不知道角度。

...然而

angular.module('archive', [])
  .factory('Loader', function ($http) {
    return $http.get('path')
      .then(function(result){
        console.log('returning: ', result);
        return result;
      });
});

和测试:

describe('TestArchive', function () {
  beforeEach(module('archive'));

  it('should load data', inject(function(Loader, $httpBackend){
    $httpBackend
      .whenGET('path')
      .respond(22);
    var resultProm = Loader;
    resultProm.then(function(result){
      console.log(result);
      // maybe add an assertion here?
    });
    $httpBackend.flush();
  }));
});

你将无法直接从你的loader指令返回数据,所以我不确定这个测试是否有意义......它应该调用两个console.log

看起来Angular已经试图完全避免异步测试,所以它在测试中使用$httpBackend.flush作为一种蹦床。