[英]AngularJS : testing a factory that returns a promise, while mocking a service that uses $http
我有一个具有以下方法的服务(除其他外),该服务返回一个$ http promise
function sessionService($http, serviceRoot) {
return {
getAvailableDates: function () {
return $http.get(serviceRoot + '/session/available_dates');
}
};
};
angular.module('app').service('sessionService', ['$http', 'serviceRoot', sessionService]);
然后,另一家工厂将其包装并将数据缓存/添加到localStorage。 这会返回定期的承诺
angular.module('app')
.factory('AvailableDates', AvailableDates);
AvailableDates.$inject = ['sessionService', '$window', '$q'];
function AvailableDates(sessionService, $window, $q) {
var availableDates = [];
return {
getAvailableDates: getAvailableDates
};
function getAvailableDates() {
var deferred = $q.defer();
var fromStorage = JSON.parse($window.sessionStorage.getItem('validDates'));
if (availableDates.length > 0) {
deferred.resolve(availableDates);
} else if (fromStorage !== null) {
deferred.resolve(fromStorage);
} else {
sessionService.getAvailableDates()
.success(function (result) {
availableDates = result;
$window.sessionStorage.setItem('validDates', JSON.stringify(availableDates));
deferred.resolve(availableDates);
});
}
return deferred.promise;
}
}
这一切都很好。 我的问题是,我无法弄清楚在模拟sessionService时如何测试此东西。 我已经阅读了所有相关的stackoverflow问题,并尝试了各种不同的方法,但没有成功。
这是我目前的测试结果:
describe('testing AvailableDates factory', function () {
var mock, service, rootScope, spy, window, sessionStorageSpy, $q;
var dates = [ "2014-09-27", "2014-09-20", "2014-09-13", "2014-09-06", "2014-08-30" ];
var result;
beforeEach(module('app'));
beforeEach(function() {
return angular.mock.inject(function (_sessionService_, _AvailableDates_, _$rootScope_, _$window_, _$q_) {
mock = _sessionService_;
service = _AvailableDates_;
rootScope = _$rootScope_;
window = _$window_;
$q = _$q_;
});
});
beforeEach(inject(function () {
// my service under test calls this service method
spy = spyOn(mock, 'getAvailableDates').and.callFake(function () {
return {
success: function () {
return [ "2014-09-27", "2014-09-20", "2014-09-13", "2014-09-06", "2014-08-30" ];
},
error: function() {
return "error";
}
};
});
spyOn(window.sessionStorage, "getItem").and.callThrough();
}));
beforeEach(function() {
service.getAvailableDates().then(function(data) {
result = data;
// use done() here??
});
});
it('first call to fetch available dates hits sessionService and returns dates from the service', function () {
rootScope.$apply(); // ??
console.log(result); // this is printing undefined
expect(spy).toHaveBeenCalled(); // this passes
expect(window.sessionStorage.getItem).toHaveBeenCalled(); // this passes
});
});
我已经尝试了各种方法,但无法弄清楚如何测试AvailableDates.getAvailableDates()调用的结果。 当我使用done()时,出现错误:超时-异步回调未在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超时下调用(我尝试覆盖此值,不走运)。
如果我取出done(),然后在调用.then之后仅调用rootScope。$ apply(),则结果将得到一个未定义的值。
我究竟做错了什么?
我在您的示例中看到了更多问题。
主要问题是模拟中的成功定义。 成功是一个函数,它具有作为参数的函数-回调。 收到数据时将调用回调-数据作为第一个参数传递。
return {
success: function (callback) {
callback(dates);
}
};
简化的工作示例在此处http://plnkr.co/edit/Tj2TZDWPkzjYhsuSM0u3?p=preview
在此示例中,模拟通过模块功能(来自ngMock)传递给提供程序-您可以通过键(服务名称)和值(实现)传递对象。 该实现将用于注入。
module({
sessionService:sessionServiceMock
});
我认为测试逻辑应该在一个函数(测试)中,将其拆分为beforeEach,测试不是一个好的解决方案。 测试是我的例子; 它更具可读性,并且具有明显分开的部分-安排,操作,声明。
inject(function (AvailableDates) {
AvailableDates.getAvailableDates().then(function(data) {
expect(data).toEqual(dates);
done();
});
rootScope.$apply(); // promises are resolved/dispatched only on next $digest cycle
expect(sessionServiceMock.getAvailableDates).toHaveBeenCalled();
expect(window.sessionStorage.getItem).toHaveBeenCalled();
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.