2014-06-05 8 views
5

Ich bin sehr neu zu Komponententests, Mocha und should.js, und ich versuche, einen Test für eine asynchrone Methode zu schreiben, die ein Versprechen zurückgibt. Hier ist mein Testcode:should.js nicht Mocha-Test fehlschlagen

var should = require("should"), 
    tideRetriever = require("../tide-retriever"), 
    moment = require("moment"), 
    timeFormat = "YYYY-MM-DD-HH:mm:ss", 
    from = moment("2013-03-06T00:00:00", timeFormat), 
    to = moment("2013-03-12T23:59:00", timeFormat), 
    expectedCount = 300; 

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function() { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
      }, 
      function(err) { // reject 
       should.fail("Promise rejected", err); 
      } 
     ); 
    }); 
}); 

Wenn ich manuell die tideRetriever.get Methode testen, es löst konsequent eine Reihe von 27 Elementen (wie erwartet), aber der Test wird nicht unabhängig von dem Wert von expectedCount scheitern. Hier ist mein einfacher manueller Test:

tideRetriever.get(from, to).then(
    function(entries) { 
     console.log(entries, entries.length); 
    }, 
    function(err) { 
     console.log("Promise rejected", err); 
    } 
); 

kann ich auch schreibe die Quelle für das Modul getestet werden, wenn es notwendig ist.

Verstehen Sie etwas über Mocha oder should.js? Jede Hilfe würde sehr geschätzt werden.

Antwort

7

UPDATE

An einem gewissen Punkt Mokka begann Promise von Test zu unterstützen Rückkehr anstelle der Zugabe done() Rückrufe. Original Antwort noch funktioniert, aber Test sieht viel sauberer mit diesem Ansatz:

it("should retrieve and parse tide CSV data", function() { 
    return tideRetriever.get(from, to).then(
     function(entries) { 
      entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
     } 
    ); 
}); 

Check out this gist für vollständige Beispiel.

ORIGINAL

VORSICHT. Akzeptierte Antwort funktioniert nur mit normalem asynchronem Code, nicht mit Promises (welcher Autor verwendet).

Der Unterschied besteht darin, dass Ausnahmen, die von Promise-Rückrufen ausgelöst werden, nicht von einer Anwendung (in unserem Fall Mocha) abgefangen werden können. Daher wird der Test durch Zeitüberschreitung und nicht durch eine tatsächliche Assertion fehlschlagen. Die Assertion kann abhängig von der Promise-Implementierung protokolliert werden oder nicht. Weitere Informationen hierzu finden Sie unter when documentation.

Um dies mit Promises richtig zu behandeln, sollten Sie err Objekt an den Rückruf done() übergeben, anstatt es zu werfen. Sie können es tun, indem Sie Promise.catch() Methode (nicht in onRejection() Rückruf von Promise.then(), weil es keine Ausnahmen von onFulfilment() Rückruf der gleichen Methode abfangen).Siehe Beispiel unten:

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function(done) { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
       done(); // test passes 
      }, 
      function(err) { // reject 
       done(err); // Promise rejected 
      } 
     ).catch(function (err) { 
      done(err); // should throwed assertion 
     }); 
    }); 
}); 

PSdone() Rückruf an drei Stellen verwendet wird, alle möglichen Fälle abzudecken. onRejection() Callback kann jedoch vollständig entfernt werden, wenn Sie keine spezielle Logik darin benötigen. Promise.catch() wird auch in diesem Fall Ablehnungen behandeln.

+0

Sie haben vergessen, "done" als Parameter der Funktion hinzuzufügen – Chaoste

+0

@Chaoste danke, behoben. –

4

Wenn Sie asynchronen Code testen, müssen Sie Mocha mitteilen, wann der Test abgeschlossen ist (unabhängig davon, ob er bestanden oder nicht bestanden wurde). Dies geschieht durch Angabe eines Arguments für die Testfunktion, das Mocha mit einer done-Funktion auffüllt. So Ihr Code könnte wie folgt aussehen:

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function(done) { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
       done(); 
      }, 
      function(err) { // reject 
       should.fail("Promise rejected", err); 
       done(); 
      } 
     ); 
    }); 
}); 

Beachten Sie, dass die Art und Weise Mokka weiß dies ein Asynchron-Test ist, und es muss warten, bis done() genannt wird, ist nur durch dieses Argument angeben.

Wenn Ihr Versprechen einen "abgeschlossenen" Handler hat, der sowohl bei Erfolg als auch bei Ausfall fehlschlägt, können Sie alternativ auch done() anrufen und so einen Anruf speichern.

Mehr Infos unter: http://mochajs.github.io/mocha/#asynchronous-code

+0

Vielen Dank. Ich dachte, die "Done" -Funktion würde nur dazu dienen, anzugeben, ob der Test synchron mit anderen Tests ausgeführt werden soll oder nicht. – SimpleJ

+0

Ich würde das verdoppeln, wenn ich könnte. Die Wichtigkeit, den "fertig" -Arg dem Test zu übergeben ("es ist die Callback-Funktion"), ist leicht zu übersehen, aber die Quelle vieler Verwirrung! – Ben

Verwandte Themen