Angular + Karma:测试异步函数

8

我有一个Angular服务,它执行一些异步操作(基于定时器)。其中一件事是你可以使用计时器定义一个“处理程序”,当计时器到期时它会触发(如下面的伪代码):

flag = false;
timer = new Timer(1000); // ms
timer.handler = function () { flag = true };

在这种简单情况下,计时器将在1秒后将标志设置为true。如何使用Angular / Karma / Jasmine进行单元测试?
从阅读文档中,我本以为以下内容可以正常工作:
... 
flag = false;
timer = new Timer(1000);
timer.handler = function () { flag = true };
expect(flag).toBe(false);
sleep(2)
expect(flag).toBe(true);
...

与道德无关,该测试由于以下原因未通过:
ReferenceError: Can't find variable: sleep

经过一些阅读,显然我不能在Jasmine中使用angular-scenario。好的,我接受了这个事实。

更新:根据评论,我测试了我的“工作中”的settimeout方法。它从未被调用。

所以这个可以工作:

... 
flag = false;
timer = new Timer(1000);
timer.handler = function () { flag = true };
expect(flag).toBe(false);
setTimeout(function () { expect(flag).toBe(true) }, 2000);
...

但感觉有点奇怪。

问题:有更好的方法吗?

趣闻:是的,我知道$timeout。我在代码深处进行了一些非常充分的原因,远离白天的光芒 =)


@rdodev:嗯,我不知道这是否是之前感觉奇怪的原因,但我刚刚测试了一下,在超时内部的expect()实际上并没有被调用(我将时间设置为10秒并重新运行了测试,但它几乎立即完成了)。 - Sir Robert
@Michael:我的计时器有一个等效于flush()的方法,但这不是我要测试的内容。 - Sir Robert
@Michael: 我根据你提供的文档想出了一个可行的解决方案。如果你想要发表回答,我会给你鸣谢。否则,我会自己发一篇详细的答案。 - Sir Robert
请提供您详细的答案! - michael
@rdodev:在这种情况下,处理程序明确按正确顺序设置。问题(现已解决)在于测试框架在计时器运行结束之前退出。我无法像使用Jasmine的angular-scenario一样引入“阻塞”序列。但是显然我可以使用run()/waitsFor() =)。 - Sir Robert
显示剩余8条评论
1个回答

12

Jasmine有一种使用waits()或waitsFor()和runs()进行异步测试的方法。请查看这里

代码可能如下所示:

... 
flag = false;
timer = new Timer(1000);
timer.handler = function () { flag = true };
expect(flag).toBe(false);
waitsFor( function() {
  return flag;
}, "timer ran");
runs( function() {
  expect(flag).toBe(true);
});
...

原帖作者备注

这是正确的解决方案,所以我标记为已接受。事实上,我最终基于这个解决方案实现了一个类似于sleep的方法,并希望分享出来,以便对他人有所帮助。

在测试文件中:

function loiter(ms) {
  var loiter = true;
  setTimeout(function () {loiter = false}, ms);
  waitsFor( function () {return !loiter}, "Loitered too long", ms + 50); 
}

it("should ...", function () {
  flag = false;
  timer = new Timer(1000);
  timer.handler = function () {flag = true};
  setTimeout(function () {expect(flag).toBe(true)}), 1100);

  loiter(1200);
})

希望这对你有帮助!让读者自己思考为什么我会以这种方式来处理,留作练习=)


这是正确的答案。Michael在上面的评论中首先回答了,但如果他不很快提供答案,我会接受你的答案为正确。谢谢=) - Sir Robert
3
如果您能解释清楚,那就太好了。我会把为什么我这样做留给读者去思考。 =) - John Haugeland
setTimeout(function () {expect(flag).toBe(true)}, 1100); - 运行良好! :-) - Thomas Kekeisen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接