2014-11-05 2 views
8

Ich versuche, einen Dienst zu testen, den ich baue, der Angulars $q Implementierung von Promises verwendet. Ich verwende eine Kombination aus Karma, Mocha, Chai, Sinon, Sinon Chai und Chai als Verheißen.

Alle Tests, die ich geschrieben habe und Versprechen zurückschicke, sind diejenigen, die ablehnen oder $q.all([ ... ]) verwenden. Ich habe alles versucht, was ich denken konnte, aber ich kann nicht finden, wo das Problem ist.

Das Folgende ist eine schlanke Version von dem, was ich testen:

"use strict"; 


describe("Promise", function() { 

    var $rootScope, 
     $scope, 
     $q; 

    beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) { 
     $rootScope = _$rootScope_; 
     $q = _$q_; 
     $scope = $rootScope.$new(); 
    })); 

    afterEach(function() { 
     $scope.$apply(); 
    }); 

    it("should resolve promise and eventually return", function() { 

     var defer = $q.defer(); 

     defer.resolve("incredible, this doesn't work at all"); 

     return defer.promise.should.eventually.deep.equal("incredible, this doesn't work at all"); 
    }); 

    it("should resolve promises as expected", function() { 

     var fst = $q.defer(), 
      snd = $q.defer(); 

     fst 
      .promise 
      .then(function (value) { 
       value.should.eql("phew, this works"); 
      }); 

     snd 
      .promise 
      .then(function (value) { 
       value.should.eql("wow, this works as well"); 
      }); 

     fst.resolve("phew, this works"); 
     snd.resolve("wow, this works as well"); 

     var all = $q.all([ 
      fst.promise, 
      snd.promise 
     ]); 

     return all.should.be.fullfiled; 
    }); 

    it("should reject promise and eventually return", function() { 
     return $q.reject("no way, this doesn't work either?").should.eventually.deep.equal("no way, this doesn't work either?"); 
    }); 

    it("should reject promises as expected", function() { 

     var promise = $q.reject("sadly I failed for some stupid reason"); 

     promise 
      ["catch"](function (reason) { 
       reason.should.eql("sadly I failed for some stupid reason"); 
      }); 

     var all = $q.all([ 
      promise 
     ]); 

     return all.should.be.rejected; 
    }); 

}); 

Die dritte, letzte und der erste Test sind diejenigen, die scheitern. Eigentlich versagt es nicht, es löst sich nur, nachdem das Timeout überschritten ist und ich bekomme eine Error: timeout of 2000ms exceeded.

EDIT: Ich habe gerade versucht, mit Kris Kowal ‚s Umsetzung der Versprechen zu testen und es funktioniert mit, dass nur in Ordnung.

P.S.Ich habe tatsächlich festgestellt, dass irgendwo in den Schalen von Mocha, Chai oder Chai As Promise etwas Zeit verbracht wird und der afterEach Hook später als die Zeitüberschreitung aufgerufen wird.

+0

Wenn ich den Pseudo-Code verstehe, sieht es so aus, als würden Sie '$ scope. $ Apply()' erst aufrufen, nachdem Sie die Erwartungen formuliert haben.Können Sie versuchen, es anzurufen, nachdem Sie das Versprechen gelöst haben? –

+0

Ich habe das auch schon probiert, ich werde bald mit diesen Tests ein Fiedel rauf und runter laufen. – Roland

+0

Running '$ scope. $ Apply()' in 'afterJeach' könnte ein Problem sein, falls Sie den Wert der Versprechen erwarten, bevor das' afterJeach' ausgeführt wird –

Antwort

3

Ich habe versucht herauszufinden, warum die Tests nicht bestanden werden, obwohl sie auf den ersten Blick erscheinen sollten. Natürlich müsste ich die $scope.$apply(); von afterEach verschieben, da das nicht der richtige Ort ist, um als @proloser zu nennen.

Obwohl ich das getan habe, sind die Tests immer noch nicht bestanden. Ich habe auch Probleme auf chai-as-promised und angular geöffnet, um zu sehen, wenn ich irgendeine Eingabe/Rückmeldung bekomme und mir wurde gesagt, dass es am wahrscheinlichsten nicht funktioniert. Der Grund liegt wahrscheinlich in der Abhängigkeit von Angular $q von der Digest-Phase, die in der Chai-as-promsied-Bibliothek nicht berücksichtigt wird.

Daher habe ich die Tests mit Q anstelle von $q überprüft und es funktionierte gut, so meine Hypothese, dass der Fehler nicht in der Chai-as-versprochene Bibliothek war.

Ich habe schließlich fallen gelassen chai-as-versprochen, und ich habe meine Prüfung neu geschrieben, anstatt mit done Rückruf des Mokka (auch hinter den Kulissen aber, chai-as-versprochen tut das gleiche):

"use strict"; 


describe("Promise", function() { 

    var $rootScope, 
     $scope, 
     $q; 

    beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) { 
     $rootScope = _$rootScope_; 
     $q = _$q_; 
     $scope = $rootScope.$new(); 
    })); 

    it("should resolve promise and eventually return", function (done) { 

     var defer = $q.defer(); 

     defer 
      .promise 
      .then(function (value) { 
       value.should.eql("incredible, this doesn't work at all"); 
       done(); 
      }); 

     defer.resolve("incredible, this doesn't work at all"); 

     $scope.$apply(); 

    }); 

    it("should resolve promises as expected", function (done) { 

     var fst = $q.defer(), 
      snd = $q.defer(); 

     fst 
      .promise 
      .then(function (value) { 
       value.should.eql("phew, this works"); 
      }); 

     snd 
      .promise 
      .then(function (value) { 
       value.should.eql("wow, this works as well"); 
      }); 

     fst.resolve("phew, this works"); 
     snd.resolve("wow, this works as well"); 

     var all = $q.all([ 
      fst.promise, 
      snd.promise 
     ]); 

     all 
      .then(function() { 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

    it("should reject promise and eventually return", function (done) { 

     $q 
      .reject("no way, this doesn't work either?") 
      .catch(function (value) { 
       value.should.eql("no way, this doesn't work either?"); 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

    it("should reject promises as expected", function (done) { 

     var promise = $q.reject("sadly I failed for some stupid reason"); 

     promise 
      ["catch"](function (reason) { 
       reason.should.eql("sadly I failed for some stupid reason"); 
      }); 

     var all = $q.all([ 
      promise 
     ]); 

     all 
      .catch(function() { 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

}); 

Die obigen Tests werden alle wie erwartet durchgeführt. Es könnte andere Wege geben, es zu tun, aber ich konnte nicht herausfinden, wie sonst. Wenn es jemand anderes tut, wäre es großartig, es gepostet zu haben, damit andere davon profitieren können.

+0

danke mann du hast mich gerettet Stunden – Blacksonic

+0

@blacksonic - kein Problem, ich verbrachte Tage selbst, bis ich eine Lösung gefunden :) – Roland

13

afterEach() wird zur Bereinigung verwendet, nicht zur Ausführung von Code nach Ihren Vorbereitungen, aber vor Ihren Tests. $scope.$apply() ist auch keine Bereinigung.

Sie müssen folgendes tun:

// setup async behavior 
var all = $q.all(x.promise, y.promise) 

// resolve your deferreds/promises 
x.reject(); y.reject(); 

// call $scope.$apply() to 'digest' all the promises 
$scope.$apply(); 

// test the results 
return all.should.be.rejected; 

Sie machen einen $apply() AFTER Ihre Tests durchgeführt werden, nicht zwischen Aufbau und Auswertung.

+0

Wenn Sie möchten, können Sie versuchen, es auf dieser [PLNK] (http://plnkr.co/edit/IusDwx7ERoiqiUYKwqKn?p=preview) zu testen, die ich es schwer habe, es einzurichten. Ich denke, eine meiner Ressourcen ist ungültig oder etwas, weil ich einen Fehler in der Konsole erhalte, der sagt, dass ich das "beforeEach" vermisse. Ich habe noch nie versucht, im Browser zu testen, daher würde es hilfreich sein, sie zum Laufen zu bringen, damit wir sehen können, ob diese Antwort tatsächlich funktioniert, und wir haben auch eine Online-Referenz, damit andere Benutzer sie sehen können. – Roland

+0

Das ist, was ich in dem Kommentar geschrieben habe, dass einige Hilfe wäre es wert, es im Browser einzurichten, wie ich es nie so gemacht habe. Und du könntest einfach einen PLNKR machen und deinen Fix anwenden und zeigen, dass es tatsächlich funktioniert, wenn du das natürlich willst. Wenn ich es lokal auf meinem Rechner nutze und sage, dass es funktioniert, wird es anderen Benutzern nicht helfen, die über dasselbe Problem stolpern. – Roland

+0

Ihr Vorschlag funktioniert nicht, und ich habe bereits versucht, was Sie vorgeschlagen haben. Deshalb habe ich gefragt, ob Sie beim Einrichten der Tests im Browser helfen können, damit Sie es auch und andere Benutzer überprüfen können, wenn es funktioniert hätte. – Roland