在AngularJS中对异步服务进行单元测试

16

我正在尝试对一个包含异步方法的服务进行单元测试,但一直没有成功。

我已经尝试使用 AngularJS 中的 $q 支持来实现 Promises。

任何帮助将不胜感激。

http://jsfiddle.net/9pBze/37/

angular.module('myapp', ['myservice']);

angular.module('myservice', []).factory('myservice', function($q) {
  var ls = {};

  ls.DoIt = function() {
    var deferred = $q.defer();

    setTimeout(function(){
        deferred.resolve(5);
    },3000);

    return deferred.promise;
  }

  return ls;

});

describe('services', function () {

    beforeEach(module('myservice'));

    it("should equal 2",  inject(function(myservice) {
        myservice.DoIt().then(function(returned) {
            expect(returned).toEqual(2);
        });        
    }));
});
2个回答

30

首先,setTimeout特别难以测试,因为很难模拟。幸运的是,AngularJS有一个包装器($timeout)可以扮演相同的角色,但可以轻松地被模拟:

  ls.DoIt = function() {
    var deferred = $q.defer();

    $timeout(function(){
        deferred.resolve(5);
    },3000);

    return deferred.promise;
  }

提供给$timeout的模拟可以让我们轻松地模拟经过的时间(使用$timeout.flush()),这意味着我们的测试可以快速运行,而不必真正等待异步事件完成(请注意,生产代码仍在使用异步API!)。

更改后的测试将如下所示:

it("should equal 5",  inject(function(myservice, $timeout) {

    var valueToVerify;
    myservice.DoIt().then(function(returned) {
      valueToVerify = returned;  
    });  
    $timeout.flush();        
    expect(valueToVerify).toEqual(5);
}));

最后附上可工作的 jsFiddle链接:http://jsfiddle.net/v9L9G/1/


感谢您提供详细的解释。我正在编写的服务使用IndexedDB并且API是异步的,我正在努力想知道当DoIt函数调用像request.onsuccess = function(event) { // Do something with request.result! deferred.resolve(result); };时如何应用上述内容。 - Hidden Developer
@Pawel 如果我正在测试一个使用DoIt模拟服务的控制器,并且在该控制器内部,DoIt处于循环中,因此它被多次调用。如何多次刷新它?难道不能让DoIt自己刷新吗?我尝试通过在其中包含this来使异步模拟自行刷新,但这似乎不太健壮。 - M.K. Safi
实际上,我之前分享的那个小例子似乎成功地让模拟器自己清空了。我遇到的问题最终证明是出在别的地方... - M.K. Safi
@pkozlowski.opensource 我们如何测试在1000毫秒后valueToVerify仍然是未定义的? - Lukasz Prus

4

这与Angular本身无关,而是与Jasmine异步测试有关。

如果您需要setTimeout,请使用Angular的$timeout。如果您希望对setTimeout/$timeout执行进行精细控制,请使用模拟时钟


谢谢你的帮助。我会查看 $timeout 的文档。 - Hidden Developer
提供的Jasmine Async链接出现404错误。我认为现在应该是http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support。 - Stephane

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