2013-07-02 23 views
43

ile zaman aşımını kullanan Birim Test Açısal Servisi Açısal servislerimden birinde düzenli aralıklarla tekrar tekrar aranmak istediğim bir fonksiyon var. Bunu $ timeout kullanarak yapmak istiyorum. - Bunu nasılUnit'sing Jasmine'in Mock Clock

var interval = 1000; // Or something 

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

_tick(); 

şu anda Yasemin ile nasıl birim test bu stumped: Bu şuna benzer? $timeout.flush() kullanırsam, işlev çağrıları süresiz olarak gerçekleşir. Jasmine'in sahte saatini kullanırsam, $timeout etkilenmemiş gibi görünüyor.

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(); 
    }); 
}); 

Bu iki varyasyon çalışması, ancak bana yardım etmezsen: Bu çalışma alabilirsiniz Temelde, ben gitmek için iyi olmalıdır önceden

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(); 
    }); 
}); 

teşekkürler!

+0

'$ rootScope' enjekte ve' $ rootScope aramayı deneyin test etmek. $ Uygulamak() 'saati ileri iterek sonra. –

cevap

51

Jasmine'in saatini kullanarak testinizi Async yapmayın. Bunun yerine, sınamanın akışını eşzamanlı olarak korumak için $timeout.flush() kullanın. Kurulumu biraz zor olabilir, ancak bir kez aldığınızda testleriniz daha hızlı ve daha kontrollü olacaktır. doğru yolu beni indirene https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618

+0

Yanıtınız, önemli bir kural kuralını yinelemenin yanı sıra sorunu da çözer: Birim testleri her zaman eşitlenmelidir – eitanfar

44

matsko cevabı @:

İşte bu yaklaşımı kullanarak yapan bir testin örneği verilmiştir. Cevabını bulmayı daha basit hale getirmek için "tam" çözümümü göndereceğimi düşündüm.

şey

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

testi

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" testinde "done()" işlevi gereksiz değil midir? $ timeout.flush(), eşzamanlı olarak $ timeeout'ta kayıtlı bekleyen tüm olayları arayacak ve bu da derhal 'expect() 'olarak adlandırılacak sözün çözülmesine neden olacaktır. –

+0

Tamamen emin değilim. Yine de bir test olabilir. – Beez

+2

@AviCherry "Bitti" geri arama parametresi olmadan, kod sifonu tetikler ancak hemen testin geçtiğini düşünür, çünkü bir zamanuyumsuz çağrının tetiklendiğini bilmez. 'Done' ile, 'done' denilene kadar testin tamamlanmayacağından emin olursunuz. Bir 'bekle' bir testi bitirmeyecek. Bir testte birden fazla beklentiniz olabilir. Ayrıca, eğer 'done' geri aramayı sağlarsanız, ancak asla çalıştırmazsanız, testiniz başarısız olacaktır çünkü Jasmine, yürütme işlemi çok uzun sürdü, çünkü test hiçbir zaman tamamlanmayacaktır. Tam geri bildirimi hatırlayamıyorum. –