Javascript 如何测试延迟的角度承诺?
我如何用模拟的角度和一段时间后解决的承诺运行测试 简单地说:下面的测试永远不会运行Javascript 如何测试延迟的角度承诺?,javascript,angularjs,unit-testing,promise,angular-promise,Javascript,Angularjs,Unit Testing,Promise,Angular Promise,我如何用模拟的角度和一段时间后解决的承诺运行测试 简单地说:下面的测试永远不会运行 var injector=angular.injector(['ngMock']); var scope=injector.get(“$rootScope”)。$new(); var q=injector.get(“$q”); var promise=函数(){ 返回q(函数(解析、拒绝){ setTimeout(函数(){ 解决(); }, 500); }); }; 允诺 .然后(函数(){ document
var injector=angular.injector(['ngMock']);
var scope=injector.get(“$rootScope”)。$new();
var q=injector.get(“$q”);
var promise=函数(){
返回q(函数(解析、拒绝){
setTimeout(函数(){
解决();
}, 500);
});
};
允诺
.然后(函数(){
document.getElementById('result').innerHTML='testrun';
});
//兑现承诺
范围。$digest()代码>
开始测试…
很明显,$q
与$rootScope.Scope模型观察机制以角度方式集成,这意味着分辨率或拒绝更快地传播到模型中,并避免不必要的浏览器重新绘制,这将导致UI闪烁。(有关更多详细信息,请检查中Q和$Q之间的差异)。我刚刚在您的代码片段中添加了范围。$apply()
:
var injector=angular.injector(['ngMock']);
var scope=injector.get(“$rootScope”)。$new();
var q=injector.get(“$q”);
var promise=函数(){
返回q(函数(解析、拒绝){
setTimeout(函数(){
解决();
作用域:$apply();
}, 500);
});
};
允诺
.然后(函数(){
document.getElementById('result').innerHTML='testrun';
});
//兑现承诺
范围。$digest()代码>
开始测试…
因此,您不应该将设置超时
功能用于angular,而可以使用angular提供的$timeout
服务。在单元测试中,超时之类的事情将无法像在页面中那样有效地计算和控制。为了解决超时问题,您可以使用$timeout.flush()
,而是这样做:
var injector = angular.injector(['ngMock']);
var scope = injector.get('$rootScope').$new();
var q = injector.get('$q');
var timeout = injector.get('$timeout');
var promise = function() {
return q(function(resolve, reject) {
timeout(function() {
resolve();
scope.$apply();
}, 500);
});
};
promise()
.then(function() {
document.getElementById('result').innerHTML = 'TEST RUN';
});
//resolve the promises
timeout.flush();
scope.$digest();
好的,我知道了
这个解决方案实际上是@mido22提出的,但我更喜欢一个稍微不同的版本,您可以从$scope和inprog的文档中得到它
根据,当您在异步函数中工作时,需要调用$apply(),比如,它明确地说,setTimeout。
更好的解释是:
直接作为从DOM或第三方库回调某个外部事件而触发的代码应该期望它永远不会从Angular内部调用,因此它调用的任何Angular应用程序代码都应该首先包装在对$apply的调用中。”
因此,解决方案是将影响Angular的所有调用(包括resolve()和reject())封装到$apply中
为了避免inprog错误,不能在另一个内部调用$apply()。本例中不是这样,但是,假设我们有另一个嵌套的setTimeout,只有最后一个被调用的应该调用$apply()
更新:
根据,避免inprog错误的最佳方法是将非角度代码包装在$timeout()中。这是angular的人推荐的策略
var injector=angular.injector(['ngMock']);
var scope=injector.get(“$rootScope”)。$new();
var q=injector.get(“$q”);
var promise=函数(){
返回q(函数(解析、拒绝){
setTimeout(函数(){
作用域$apply(函数(){
解决();
});
}, 500);
});
};
允诺
.然后(函数(){
document.getElementById('result').innerHTML='testrun';
});
开始测试…
您是否需要让超时实际运行500毫秒(或者可以是1毫秒1000000毫秒?),或者只是从超时开始计算,然后让承诺得到解决?超时只是一个例子,事实上,可以使用$timeout而不是setTimeout轻松解决它。问题是,无论何时异步使用$q,除非知道何时调用作用域,否则无法对其进行测试。$digest();这并不总是事先知道的。为什么你要用angular测试非角度代码?因为我正在制作一些非角度代码,角度友好。具体地说,我正在将Cordova插件与Ionic集成。我已经检查了这些人在中做了什么,他们还使用了$q承诺(请参阅a)。在他们的测试中,他们确实调用了$rootScope.$digest();
(请参阅),但这在我的情况下不起作用:(谢谢你的建议,但我认为这是不可接受的,原因有两个:1)函数“promise”是正在测试的函数,不应该将其逻辑与测试的逻辑混在一起;2)我在代码中尝试过这种方法,我得到了一个errors@dariosalvi您得到的是inprog错误,因为它(scope.$apply();
)是不安全的,一种方法是在执行之前检查状态,另一种方法是使用浏览器的默认承诺(它是polyfill for!@#类似IE),在这里使用$q有什么特别的原因吗?我之所以使用$q,是因为它是标准的angular promise实现,不需要导入任何其他东西,也不必担心不同的API。也许,在模拟时,你不能这样使用$q,这对可测试性有点不利。谢谢你的建议。正如我在第一篇评论中所说,timeout只是一个例子,我知道我可以使用$timeout,但这不是我的观点。我的观点是:当我有一些异步代码时,如何使用$q进行测试?具体地说,在我的具体案例中,我有一组对Cordova插件的调用,所以没有角度$-我可以使用的东西。