如何测试angularjs中的承诺

时间:2014-01-09 07:47:24

标签: unit-testing angularjs jasmine

我遇到过一个我无法通过考试的案例。

以下是测试:

it('should accept an fucntion run it immediately', inject(function($rootScope, ready) {
    var spy = jasmine.createSpy('ready').andCallFake(function(){
        console.log("I'm ready");
    });
    ready.done(spy);
    expect(spy).toHaveBeenCalled();
}));

这是代码:

angular.module('myApp').factory('ready', function($q, _, $rootScope){

    var defer = $q.defer();

    //in real case it's actually calling 3rd party code, so no $timeout
    _.defer(function(){
        $rootScope.$apply(function(){
            defer.resolve();
        });
    });

    return {
        done: function(fn){
            defer.promise.then(fn);
        }
    };
});

I'm ready的日志确实出现了,但测试仍然失败。所以我认为它只是在jasmine中处理异步流的问题。但我想不出用茉莉花的runswaitsFor进行测试。

1 个答案:

答案 0 :(得分:1)

我怀疑测试失败,然后按顺序出现console.log,因为在_.defer调用其回调之后才会解析promise,这是在当前调用堆栈之后清除。

您需要的是一种强制下划线/ lodash _.defer来调用其回调/承诺的方法,这样您在工厂的承诺就会立即得到解决。如果您使用$timeout,则可以在测试中调用$timeout.flush(),但据我所知,下划线/ lodash没有这样的内容。

但是,在测试之前,你应该能够注入一个带有defer函数的模拟'_',它立即调用它的回调函数:

beforeEach(module(function($provide) {
  $provide.value('_', {
    'defer': function(callback) {callback()};
  });    
}));

在您的实际案例中,您需要执行类似上述操作,注入模拟第三方服务并强制其完成,以便在测试中expect调用之前解决您的承诺。

如果由于某种原因你不能注入第三方代码的模拟版本,你可以使测试异步,如http://pivotal.github.io/jasmine/#section-Asynchronous_Support所述,但是如果可能的话应该避免这样做,因为它会进行测试跑得慢。

相关问题