2013-03-18 14 views
16

Próbuję przetestować usługę, która ma asynchroniczne metody, ale nie mam szczęścia.Jednostka testująca usługę asynchroniczną w angularjs

Próbowałem wdrożyć za pomocą obietnic za pomocą wsparcia $ q w angularjs.

Każda pomoc zostanie doceniona.

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

Odpowiedz

29

Przede wszystkim, jest szczególnie trudne setTimeout przetestować ponieważ trudno drwić. Na szczęście angularjs ma otoki wokół niego ($timeout), który odgrywa taką samą rolę, ale może być łatwo szydzili:

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

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

    return deferred.promise; 
    } 

makiety przewidziany $timeout pozwala nam łatwo symulować upływ czasu (z $timeout.flush()), co oznacza nasze testy można uruchomić szybko, bez czekania na zakończenie zdarzenia asynchronicznego (pamiętaj, że kod produkcyjny nadal używa async API!).

Zmienione testy wyglądałby następująco:

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

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

i wreszcie jsFiddle pracy: http://jsfiddle.net/v9L9G/1/

+0

Dzięki za szczegółowe wyjaśnienie. Usługa, którą piszę używa IndexedDB i api jest asynchroniczna i walczę o to, w jaki sposób mogę zastosować powyższe, gdy funkcja DoIt nazywa coś w stylu request.onsuccess = function (event) { // Zrób coś za pomocą request.result ! deferred.resolve (wynik); }; – user1405779

+0

@Pawel Co jeśli testuję kontroler korzystający z usługi "Do It", a wewnątrz kontrolera, 'DoIt' jest w pętli, więc jest wywoływany wiele razy. Jak mogę spłukać to wiele razy? Czy nie można uzyskać polecenia "Do It", aby samo się przepłukać? Próbowałem uzyskać asynchroniczną próbę, aby przepłukać się, włączając w to [this] (http://jsfiddle.net/cUEQ8/), ale to nie wydaje się bardzo solidne. –

+0

Właściwie to skrzypce, które udostępniłem powyżej, wydają się skutecznie udawać, że się spłukują. Problem okazał się być gdzieś innym ... –

4

To nie jest związane z samym kątowym, ale Jasmine async tests.

Jeśli potrzebujesz setTimeout, użyj Angular $timeout. A jeśli chcesz mieć dokładną kontrolę nad wykonaniem setTimeout/$ timeout, użyj mocked Clock.

+0

Dzięki za pomoc. Zapoznam się z dokumentacją $ timeout. – user1405779

+0

Podany link do Jasmine Async 404ed. Sądzę, że teraz jest http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support – Stephane

+0

Miałeś rację. Dzięki @StephaneEybert –

Powiązane problemy