我正在尝试测试非常简单的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
看到的那样,它不会发生,result
是undefined
。
知道什么是错的吗?
答案 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
作为一种蹦床。