2013-07-02 12 views
43

私は定期的に繰り返し呼び出される私の角度サービスの1つの中に機能を持っています。 $ timeoutを使ってこれをしたいと思います。

var interval = 1000; // Or something 

var _tick = function() { 
    $timeout(function() { 
     doStuff(); 
     _tick(); 
    }, interval); 
}; 

_tick(); 

現時点でジャスミンで単体テストを行う方法については、私は困惑しています。どうすればよいですか? $timeout.flush()を使用すると、関数呼び出しは無期限に発生します。ジャスミンのモッククロックを使用すると、$timeoutは影響を受けていないようです。基本的に私はこの作業を得ることができる場合、私は行くために良いことがあります:

describe("ANGULAR Manually ticking the Jasmine Mock Clock", function() { 
    var timerCallback, $timeout; 

    beforeEach(inject(function($injector) { 
     $timeout = $injector.get('$timeout'); 
     timerCallback = jasmine.createSpy('timerCallback'); 
     jasmine.Clock.useMock(); 
    })); 

    it("causes a timeout to be called synchronously", function() { 
     $timeout(function() { 
      timerCallback(); 
     }, 100); 
     expect(timerCallback).not.toHaveBeenCalled(); 
     jasmine.Clock.tick(101); 
     expect(timerCallback).toHaveBeenCalled(); 
    }); 
}); 

これらの2つのバリエーションは動作しますが、私を助けていない:事前に

describe("Manually ticking the Jasmine Mock Clock", function() { 
    var timerCallback; 

    beforeEach(function() { 
     timerCallback = jasmine.createSpy('timerCallback'); 
     jasmine.Clock.useMock(); 
    }); 

    it("causes a timeout to be called synchronously", function() { 
     setTimeout(function() { 
      timerCallback(); 
     }, 100); 
     expect(timerCallback).not.toHaveBeenCalled(); 
     jasmine.Clock.tick(101); 
     expect(timerCallback).toHaveBeenCalled(); 
    }); 
}); 

describe("ANGULAR Manually flushing $timeout", function() { 
    var timerCallback, $timeout; 

    beforeEach(inject(function($injector) { 
     $timeout = $injector.get('$timeout'); 
     timerCallback = jasmine.createSpy('timerCallback'); 
    })); 

    it("causes a timeout to be called synchronously", function() { 
     $timeout(function() { 
      timerCallback(); 
     }, 100); 
     expect(timerCallback).not.toHaveBeenCalled(); 
     $timeout.flush(); 
     expect(timerCallback).toHaveBeenCalled(); 
    }); 
}); 

ありがとう!

+0

をテストするためのもの。 –

答えて

51

Jasmineのクロックを使用して非同期テストを実行しないでください。代わりに、$timeout.flush()を使用して、テストフローを同期的に維持します。それは設定するのが少し難しいかもしれませんが、一度それを取得すると、あなたのテストはより速くより制御されます。ここで

は、このアプローチを使用しないテストの例です:matskoの答え@ https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618

+0

あなたの答えはこの問題を解決するだけでなく、重要な経験則を繰り返します。ユニットテストは常に同期する必要があります – eitanfar

44

は正しい道を私を導きました。私は答えを見つけるのが簡単になるように私の "完全な"ソリューションを投稿するつもりだと思った。

`$ rootScope`を注入し、` $ rootScopeを呼び出してみてください。$前方にクロックを押した後 `)(適用

angular.module("app").service("MyService", function() { 
    return { 
     methodThatHasTimeoutAndReturnsAPromise: function($q, $timeout) { 
      var deferred = $q.defer(); 
      $timeout(function() { 
       deferred.resolve(5); 
      }, 2000); 
      return deferred.promise; 
     } 
    }; 
}); 

テスト

describe("MyService", function() { 
    var target, 
     $timeout; 
    beforeEach(inject(function(_$timeout_, MyService) { 
     $timeout = _$timeout_; 
     target = MyService; 
    })); 
    beforeEach(function(done) { 
     done(); 
    }); 
    it("equals 5", function(done) { 
     target.methodThatHasTimeoutAndReturnsAPromise().then(function(value) { 
      expect(value).toBe(5); 
      done(); 
     }); 
     $timeout.flush(); 
    }); 
}); 
+0

"equals 5"テストの 'done()'は冗長ではありませんか? '$ timeout.flush()'は、$ timeoutに登録されている保留中のイベントをすべて同期的に呼び出します。これにより、約束が解決され、即座に 'expect()'が呼び出されます。 –

+0

私は完全にはわかりません。しかし、テストの価値があるかもしれません。 – Beez

+2

@AviCherry 'done'コールバックパラメータがなければ、コードはフラッシュをトリガしますが、非同期呼び出しがトリガされたことを知らないため、テストが成功したとみなします。 'done'では、' done'が呼び出されるまでテストが完了しないことを確認します。 'expect'はテストを終了しません。あなたは、テストで複数の期待を持つことができます。 また、 'done'コールバックを提供してもそれを実行しないと、テストが完了しないので、Jasmineが' '実行時間が長すぎました。正確なフィードバックを覚えていない。 –

関連する問題