2015-01-27 3 views
6

Ich bin ein Knotenmodul bauen und versuche, mein Bestes zu geben, Unit-Test die Hölle daraus. Ich habe Mokka und Chai eingerichtet, um die Testbehandlung durchzuführen. Ich habe ein Problem beim Testen meiner asynchronen Methoden (Methoden, die Versprechen zurückgeben).Assert ist Breaking Async-Funktion in Mokka-Test

Im folgenden Test teste ich eine Methode auf einem "Upgrade" -Objekt.

it('Should return a list of versions for the default git repo', function (done) { 
    fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG)); 

    var upgrade = new Upgrade({ 
     quiet: true 
    }); 

    upgrade.getVersions().then(function (versions) { 
     assert(versions && versions.length > 0, 'Should have at least one version.'); 
     assert.equal(1, 2); // this throws the exception which causes the test case not even exist 
     done(); 
    }, done); 
    }); 

Der getVersions() Aufruf gibt ein Versprechen, wie die Methode Asynchron ist. Wenn das Versprechen aufgelöst wird, möchte ich den in der Variablen versions zurückgegebenen Wert testen.

Die assert(versions && versions.length > 0, 'Should have at least one version.'); ist der eigentliche Test. Ich fügte assert.equal(1, 2); hinzu, weil ich bemerkte, dass, wenn der Test ausfallen sollte, der Testfall nicht sogar in der Testliste auftauchen würde.

Ich nehme an, dass der Assert-Aufruf eine Ausnahme auslöst, die Mocha abholen sollte. Jedoch wird es in der Verhinderungsfunktion then Handler-Funktion gefangen.

Was geht hier vor? Warum wird der Testfall in der Liste nicht angezeigt, wenn die Assert in dieser Methode fehlschlägt (es wird nicht als fehlgeschlagen angezeigt; wie es nicht existiert)?

Antwort

11

Der Kern des Problems ist, dass der Code, den Sie haben im Wesentlichen ist:

try { 
    var versions = upgrade.getVersions(); 
} catch (err){ 
    return done(err); 
} 

assert(versions && versions.length > 0, 'Should have at least one version.'); 
assert.equal(1, 2); // this throws the exception which causes the test case not even exist 
done(); 

auf das Sehen, sollte es klar sein, dass, wenn die Assertionen werfen, dann weder Rückruf wird ausgeführt.

try { 
    var versions = upgrade.getVersions(); 
    assert(versions && versions.length > 0, 'Should have at least one version.'); 
    assert.equal(1, 2); // this throws the exception which causes the test case not even exist 
    done(); 
} catch (err){ 
    return done(err); 
} 

ist wie das, was Sie wollen, was sein würde:

upgrade.getVersions().then(function (versions) { 
    assert(versions && versions.length > 0, 'Should have at least one version.'); 
    assert.equal(1, 2); // this throws the exception which causes the test case not even exist 
}).then(done, done); 

Knoten, dass dies die Behauptungen ausführt und dann die Rückrufe in einen sekundären .then() bewegen, die die Fehler immer behandelt.

Das heißt, wäre es viel einfacher sein, einfach das Versprechen als

return upgrade.getVersions().then(function (versions) { 
    assert(versions && versions.length > 0, 'Should have at least one version.'); 
    assert.equal(1, 2); // this throws the exception which causes the test case not even exist 
}); 

zurückzukehren, um die Versprechen selbst ohne den Rückruf zu lassen Mocha überwachen.

+0

Ich bin mir nicht sicher, ob ich verstehe, warum diese Antwort funktioniert. Der ursprüngliche Code ist im Grunde: async(). Dann (function() { werfen neue Error(); // wenn diese Zeile löst, dann geht dies an die .catch() Handler done(); }) .catch (erledigt) // registriere done() als Fehlerhandler. Wenn der throw passiert, wird der 'done()' Aufruf im 'then()' Handler nicht ausgeführt, aber der '.catch()' Handler wird stattdessen aufgerufen ... was immer noch 'done' ist. –

+0

Whoops, Kommentare erlauben keine Codeblöcke und sperren nach 5 Minuten. Sorry wegen der Mist-Formatierung :( –

+0

'.dann (fn, done)' ist nicht äquivalent zu '.then (fn) .catch (done);', das ist der Kern des Unterschieds. In der ersten wenn 'fn' würfelt Es ist ein unbehandelter Fehler, im zweiten Beispiel wird "done" aufgerufen. – loganfsmyth

4

Der Test wird nicht in der Liste angezeigt, bis Sie den Callback aufrufen, was nie passiert, wenn diese Assert fehlschlägt. Sie müssten .catch(done) auf das endgültige Versprechen anrufen, um sicherzustellen, done wird immer aufgerufen.

Der Test wird angezeigt, wenn Sie ihm einen Zeitüberschreitungswert geben, den Sie wahrscheinlich tun sollten.

Alles, was gesagt wird, mocha versteht Versprechungen. Sie brauchen gar nicht mit Rückrufe zu beschäftigen:

it('Should return a list of versions for the default git repo', function() { 
    fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG)); 

    var upgrade = new Upgrade({ 
     quiet: true 
    }); 

    return upgrade.getVersions().then(function (versions) { 
     assert(versions && versions.length > 0, 'Should have at least one version.'); 
     assert.equal(1, 2); 
    }); 
    }); 
+0

Ich wünschte, ich könnte beide Ihre Antworten akzeptieren! –