2016-07-08 9 views
1

Ich versuche, Mocha-Tests für meine Controller mit einer Konfiguration zu erstellen, die async geladen werden muss. Unten ist mein Code. Wenn der Mokka- Test ausgeführt wird, führt er jedoch keine Tests aus und zeigt 0 passing an. Die console.log s werden nie aufgerufen. Ich habe versucht, before(next => config.build().then(next)) innerhalb der beschreiben, aber obwohl die Tests laufen, before wird nie aufgerufen. Gibt es eine Möglichkeit, die Konfiguration einmal zu laden, bevor Tests ausgeführt werden?Wie kann ich meine Testsuite asynchron erstellen?

'use strict'; 

const common = require('./common'); 
const config = require('../config'); 

config 
    .build() 
    .then(test); 


function test() { 
console.log(1); 
    describe('Unit Testing',() => { 
console.log(2); 
     require('./auth'); 
    }); 
} 
+0

Dies ist, wie ich bin mit 'before', die nicht genannt werden:' beschreibt ('Unit Testing',() => { vor (next = > config.build(). dann (next)); require ('./ auth'); }); ' – terpak

Antwort

2

Sie sollten Mocha laufen mit der --delay Option, und dann run() benutzen, wenn Sie Ihre Testsuite Gebäude fertig sind. Hier ist ein Beispiel aus dem Code abgeleitet Sie in der Frage zeigen:

'use strict'; 

function test() { 
    console.log(1); 
    describe('Unit Testing',() => { 
     console.log(2); 
     it("test",() => { 
      console.log(3); 
     }); 
    }); 

    // You must use --delay for `run()` to be available to you. 
    run(); 
} 

setTimeout(test, 1000); 

I setTimeout bin mit einem asynchronen Betrieb zu simulieren. Mit --delay und run() können Sie eine Suite erstellen, die das Ergebnis einer asynchronen Berechnung ist. Beachten Sie jedoch, dass die Suite in einem Schuss gebaut werden muss. (Sie können nicht einen asynchronen Prozess innerhalb describe haben, die Anrufe zu it machen Das wird nicht funktionieren..)


Eine Sache, die Sie sollten auf jeden Fall nicht ist, was rob3c suggests: describe oder it (oder beide) Aufruf von innen ein Haken. Dies ist ein Fehler, den die Leute immer wieder machen, deshalb lohnt es sich, im Detail zu sprechen. Das Problem ist, dass es von Mocha einfach nicht unterstützt wird und daher keine etablierte Semantik mit dem Aufruf von describe oder it von innerhalb eines Hooks verbunden ist. Oh, ist es möglich, einfache Beispiele zu schreiben, wie man arbeiten könnte erwarten, aber:

  1. Wenn die Suite komplexer wird, das Verhalten der Suite nicht mehr entspricht etwas sinnvoll.

  2. Da mit diesem Ansatz keine Semantik verbunden ist, können neuere Mocha-Versionen die fehlerhafte Verwendung anders behandeln und Ihre Suite beschädigen.

dieses einfache Beispiel betrachten:

const assert = require("assert"); 

const p = Promise.resolve(["foo", "bar", "baz"]); 

describe("top",() => { 
    let flag; 
    before(() => { 
     flag = true; 
     return p.then((names) => { 
      describe("embedded",() => { 
       for (const name of names) { 
        it(name,() => { 
         assert(flag); 
        }); 
       } 
      }); 
     }); 
    }); 

    after(() => { 
     flag = false; 
    }); 

    it("regular test",() => { 
     assert(flag); 
    }); 
}); 

Wenn wir es laufen, erhalten wir:

top 
    ✓ regular test 

    embedded 
    1) foo 
    2) bar 
    3) baz 

    1 passing (32ms) 
    3 failing 

    // [stack traces omitted for brevity] 

Was hier los? Sollten nicht alle Tests bestanden werden? Wir setzen flag auf true im before Haken für die top beschreiben. Alle Tests, die wir darin erstellen, sollten flag als true sehen, nicht? Der Hinweis ist in der Ausgabe oben: wenn wir Tests innerhalb eines Hooks erstellen, wird Mocha die Tests irgendwo setzen, aber es kann nicht an einem Ort sein, der die Struktur der describe Blöcke im Code widerspiegelt. Was passiert in diesem Fall ist, dass Mocha fügt nur die Tests erstellt in den Haken das Ende der Suite, außerhalb der top beschreiben, so dass die after Hook läuft vor den dynamisch erstellten Tests, und wir erhalten ein kontraintuitives Ergebnis .

Mit --delay und run(), können wir eine Suite schreiben, die mit Intuition in einer Art und Weise concordant verhält:

const assert = require("assert"); 

const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => { 
    describe("top",() => { 
     let flag; 
     before(() => { 
      flag = true; 
     }); 

     after(() => { 
      flag = false; 
     }); 

     describe("embedded",() => { 
      for (const name of names) { 
       it(name,() => { 
        assert(flag); 
       }); 
      } 
     }); 

     it("regular test",() => { 
      assert(flag); 
     }); 
    }); 
    run(); 
}); 

Ausgang:

top 
    ✓ regular test 
    embedded 
     ✓ foo 
     ✓ bar 
     ✓ baz 


    4 passing (19ms) 
+0

* Es ist * möglich, dynamische Tests asynchron pro Datei zu erstellen. Siehe meine Antwort unten für einen Weg, der nicht das '--delay'-root suite-Verzögerungsflag oder den einzelnen globalen 'run()' -Hook verwendet: https://Stackoverflow.com/a/48572080/871990 – rob3c

-1

Sie nur die Logik des Tests trennen konnte und laden ganz , wickeln Sie den Loader in ein Versprechen, das den Test blockiert, bis die Konfiguration ausgeführt wird (sehr einfach mit async/warten Sie, wenn Sie node8 verwenden, andernfalls nur Promise.each die Ergebnisse).

Wenn Sie das wirklich nicht tun möchten, könnten Sie Ihr Testframework Promisifizieren, das Ihnen dann erlauben würde, alle beschreiben/es Blöcke als asynchronen Code zu behandeln.

-1

Das Problem bei der Verwendung der --delay Befehlszeilenparameter und run() Rückruf, der in seiner akzeptierten Antwort erwähnt @Louis, ist, dass run() ein einziger globaler Haken ist dass delays the root test suite. Daher müssen Sie alle auf einmal aufbauen (wie er bereits erwähnt hat), was die Organisation von Tests zu einem Ärger machen kann (um es gelinde auszudrücken).

Allerdings mag ich magischen Flags wann immer möglich vermeiden, und ich möchte sicherlich nicht meine gesamte Testsuite in einem einzigen globalen run() Callback verwalten müssen. Glücklicherweise gibt es eine Möglichkeit, um dynamisch die Tests auf einer Pro-Datei-Basis zu erstellen, und es ist keine besonderen Fahnen benötigen, entweder :-)

dynamisch It() Tests in jede Testquelldatei unter Verwendung von Daten erstellen erhalten asynchron können Sie (0) den before() Hook mit einem Platzhalter It() testen, um sicherzustellen, dass Mokka wartet, bis before() ausgeführt wird. Hier ist das Beispiel von my answer to a related question, für die Bequemlichkeit:

before(function() { 
    console.log('Let the abuse begin...'); 
    return promiseFn(). 
     then(function (testSuite) { 
      describe('here are some dynamic It() tests', function() { 
       testSuite.specs.forEach(function (spec) { 
        it(spec.description, function() { 
         var actualResult = runMyTest(spec); 
         assert.equal(actualResult, spec.expectedResult); 
        }); 
       }); 
      }); 
     }); 
}); 

it('This is a required placeholder to allow before() to work', function() { 
    console.log('Mocha should not require this hack IMHO'); 
}); 
+0

Was Sie zeigen wird von Mocha nicht unterstützt. Es gibt keine definierte Semantik zum Aufruf von 'describe' oder' it' aus einem 'before'-Hook. Für einfache Beispiele (wie Ihre hier) mag es aussehen, als ob es eine definierte Semantik dafür gibt, aber es gibt einfach keine. Wenn es tut, was Sie erwarten, ist das nur Glück, nicht Design. Ich garantiere Ihnen, dass Sie bei komplexeren Suites in Situationen geraten, in denen die Tests, die Sie Ihrem Hook hinzufügen möchten, an Stellen im Testbaum landen, die für Sie seltsam erscheinen. – Louis

+0

@Louis Ich habe es jetzt seit ein paar Jahren ohne Probleme oder Überraschungen verwendet, also schätze ich bin nur ein Glück :-) – rob3c

+0

Ja, du hattest Glück. Da das, was Sie tun, nicht unterstützt wird, könnte eine neue Version von Mocha herausgekommen sein, die Ihren Code zerstört. Wenn Sie einen Problembericht geöffnet hätten, wäre die Antwort "Sie versuchen, etwas zu tun, was Mocha nicht unterstützt" und das Problem wäre geschlossen worden. – Louis