Angular服务的Jasmine测试不能解决延迟调用
Jasmine test for Angular service does not resolve deferred call
我是Angular的新手,我正在测试一个运行在API级服务上的Angular服务,它封装了一堆对REST服务的调用。因为它与HTTP请求一起工作,服务的两个部分都与承诺一起工作,看起来工作得很好,但我在获得承诺行为的任何测试时遇到了麻烦。
我的服务代码的相关部分(粗略简化)如下所示:
angular.module('my.info')
.service('myInfoService', function (infoApi, $q) {
infoLoaded: false,
allInfo: [],
getInfo: function () {
var defer = $q.defer();
if (infoLoaded) {
defer.resolve(allInfo);
} else {
infoApi.getAllInfo().then(function (newInfo) {
allInfo = newInfo;
infoLoaded = true;
defer.resolve(allInfo);
});
}
return defer.promise;
}
});
当我设置我的mock时,我有这样的东西:
describe("Info Service ",
function() {
var infoService, infoRequestApi, $q;
beforeEach(module("my.info"));
beforeEach(function() {
module(function($provide) {
infoRequestApi = {
requestCount: 0,
getAllInfo: function() {
var defer = $q.defer();
this.requestCount++;
defer.resolve( [ "info 1", "info 2" ] );
return defer.promise;
}
};
$provide.value("infoApi", infoRequestApi);
});
inject(function( _myInfoService_, _$q_ ) {
infoService = _myInfoService_,
$q = _$q_;
});
});
it("should not fail in the middle of a test", function(done) {
infoService.getInfo().then( function(infoResult) {
// expectation checks.
expect( true ).toBeTrue();
}).finally(done);
});
});
任何同步测试都通过得很好,但是当我尝试运行这样的任何测试时,我得到一条消息说:Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
看起来好像是Angular。mock处理延迟的结果,导致其失败。当我逐步完成测试时,模拟对象的defer
变量被正确设置,但是服务中的then
语句从未被调用。我哪里做错了?
简短回答
你必须开始消化循环。您可以使用$rootScope.$apply()
。
it("should not fail in the middle of a test", inject(function($rootScope) {
var actualResult = null;
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
$rootScope.$apply();
expect(actualResult).toEqual(["info 1", "info 2"]);
}));
注意
我不会尝试创建一个假的infoRequestApi
服务的方式,你正在做它。您也应该注入该服务,并监视其功能。例如,像这样:
it("should not fail in the middle of a test", inject(function($rootScope, infoApi, $q) {
var deferred = $q.defer();
spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise);
var actualResult = null;
var expectedResult = ["info 1", "info 2"];
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
deferred.resolve(expectedResult);
$rootScope.$apply();
expect(actualResult).toBe(expectedResult);
}));
重构
同样,您的代码可以简化一点(未经测试,但接近我期望看到的)。
angular.module('my.info')
.service('myInfoService', function (infoApi, $q) {
return {
infoLoaded: false,
allInfo: [],
getInfo: function () {
var self = this;
return this.infoLoaded ? $q.resolve(this.allInfo) :
infoApi.getAllInfo().then(function (newInfo) {
self.allInfo = newInfo;
self.infoLoaded = true;
});
}
};
});
describe("Info Service ", function() {
var infoService, infoApi, $q, $rootScope;
beforeEach(module("my.info"));
beforeEach(inject(function( _myInfoService_, _$q_ _$rootScope_, _infoApi_) {
infoService = _myInfoService_,
$q = _$q_;
$rootScope = _$rootScope_;
infoApi = _infoApi_;
});
it("should do something", function() { // update message
var deferred = $q.defer();
spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise);
var actualResult = null;
var expectedResult = ["info 1", "info 2"];
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
deferred.resolve(expectedResult);
$rootScope.$apply();
expect(actualResult).toBe(expectedResult);
});
});
相关文章:
- 可以简化嵌套的延迟Q Promises解析吗
- 如何解决Yii中的页面刷新问题
- 测试Angular Service解决错误回调中的promise
- onclick函数需要双击,因为类分配延迟
- jQuery通过步骤的自排队循环来解决延迟问题
- 如何通过justinaguilar.com设置动画延迟?[解决]
- 解决延迟问题无法按预期进行
- 同步解决HTTP延迟承诺
- jQuery如何解决<脚本延迟>问题
- 解决所有延迟问题后执行某些操作
- javascript的同步延迟或命令解释器的setTimeout解决方案
- jQuery延迟或JavaScript SetTimeOut简单的解决方案
- JavaScript滑块插件mighyslider -需要延迟解决方案
- 延迟不解决
- 在页面加载后延迟javascript和jquery的最终解决方案
- jQuery图像延迟加载仍然是优化网页加载速度的解决方案
- Angular服务的Jasmine测试不能解决延迟调用
- 用承诺解决jQuery延迟
- 使用鼓机的设置超时解决延迟问题
- 延迟解决始终在尝试捕获范围内