So testen Sie Ihren JavaScript-Code mit QUnit

QUnit, entwickelt vom jQuery-Team, ist ein großartiger Rahmen für das Testen von JavaScript-Einheiten. In diesem Lernprogramm werde ich vorstellen, was genau QUnit ist und warum es wichtig ist, den Code gründlich zu testen.

Was ist QUnit?

QUnit ist ein leistungsfähiges JavaScript-Komponententest-Framework, mit dem Sie Code debuggen können. Es wurde von Mitgliedern des jQuery-Teams geschrieben und ist die offizielle Testsuite für jQuery. QUnit ist jedoch allgemein genug, um regulären JavaScript-Code zu testen, und es ist sogar in der Lage, serverseitiges JavaScript über JavaScript-Engine wie Rhino oder V8 zu testen.

Machen Sie sich keine Sorgen, wenn Sie mit der Idee des "Unit-Tests" nicht vertraut sind. Es ist nicht zu schwer zu verstehen:

Bei der Computerprogrammierung ist das Testen von Einheiten ein Software-Überprüfungs- und -Validierungsverfahren, bei dem ein Programmierer prüft, ob einzelne Einheiten des Quellcodes für die Verwendung geeignet sind. Eine Einheit ist der kleinste überprüfbare Teil einer Anwendung. Bei der prozeduralen Programmierung kann eine Einheit eine individuelle Funktion oder Prozedur sein.

Dies wird aus Wikipedia zitiert. Einfach ausgedrückt, Sie schreiben Tests für jede Funktionalität Ihres Codes. Wenn alle Tests bestanden sind, können Sie sicher sein, dass der Code fehlerfrei ist (hängt meistens davon ab, wie gründlich Ihre Tests sind)..

Warum Sie Ihren Code testen sollten

Wenn Sie zuvor noch keine Komponententests geschrieben haben, wenden Sie Ihren Code wahrscheinlich direkt auf eine Website an. Klicken Sie eine Weile, um zu sehen, ob ein Problem auftritt, und versuchen Sie es zu beheben, sobald Sie einen gefunden haben. Es gibt viele Probleme mit dieser Methode.

Erstens ist es sehr langweilig. Das Klicken ist eigentlich kein einfacher Job, da Sie darauf achten müssen, dass alles angeklickt wird und Sie wahrscheinlich ein oder zwei Dinge vermissen. Zweitens ist alles, was Sie zum Testen getan haben, nicht wiederverwendbar, was bedeutet, dass es nicht leicht ist, Regressionen zu finden. Was ist eine Regression? Stellen Sie sich vor, Sie haben Code geschrieben und getestet, alle gefundenen Fehler behoben und veröffentlicht. Anschließend sendet ein Benutzer ein Feedback zu neuen Fehlern und fordert einige neue Funktionen an. Sie gehen zurück zum Code, beheben diese neuen Fehler und fügen diese neuen Funktionen hinzu. Als Nächstes könnten einige der alten Fehler erneut auftreten, die als "Regressionen" bezeichnet werden. Sehen Sie, jetzt müssen Sie erneut klicken, und Sie werden wahrscheinlich diese alten Fehler nicht mehr finden. Selbst wenn Sie dies tun, dauert es eine Weile, bis Sie feststellen, dass das Problem durch Regressionen verursacht wird. Beim Komponententest schreiben Sie Tests, um Fehler zu finden. Sobald der Code geändert wurde, filtern Sie ihn erneut durch die Tests. Wenn eine Regression auftritt, werden einige Tests definitiv nicht bestanden und Sie können sie leicht erkennen, wenn Sie wissen, welcher Teil des Codes den Fehler enthält. Da Sie wissen, was Sie gerade geändert haben, können Sie das Problem leicht beheben.

Ein weiterer Vorteil von Unit-Tests ist insbesondere für die Webentwicklung: Es erleichtert das Testen der Cross-Browser-Kompatibilität. Führen Sie einfach Ihre Tests in verschiedenen Browsern aus. Wenn in einem Browser ein Problem auftritt, beheben Sie das Problem und führen Sie diese Tests erneut aus. Stellen Sie sicher, dass keine Regression in anderen Browsern auftritt. Sie können sicher sein, dass alle Zielbrowser unterstützt werden, sobald alle die Tests bestanden haben.

Ich möchte eines von John Resigs Projekten erwähnen: TestSwarm. Sie führt das Testen von JavaScript-Einheiten auf eine neue Ebene, indem es verteilt wird. Es ist eine Website, die viele Tests enthält. Jeder kann dorthin gehen, einige Tests ausführen und das Ergebnis an den Server zurückgeben. Auf diese Weise kann Code auf verschiedenen Browsern und sogar auf verschiedenen Plattformen sehr schnell getestet werden.

So schreiben Sie Komponententests mit QUnit

Wie schreibt man also Komponententests mit QUnit genau? Zunächst müssen Sie eine Testumgebung einrichten:

    QUnit Test Suite         

QUnit Test Suite

    Wie Sie sehen, wird hier eine gehostete Version des QUnit-Frameworks verwendet.

    Der Code, der getestet werden soll, sollte in myProject.js eingefügt werden, und Ihre Tests sollten in myTests.js eingefügt werden. Um diese Tests auszuführen, öffnen Sie diese HTML-Datei einfach in einem Browser. Nun ist es an der Zeit, einige Tests zu schreiben.

    Die Bausteine ​​der Komponententests sind Zusicherungen.

    Eine Assertion ist eine Anweisung, die das Ergebnis Ihres Codes vorhersagt. Wenn die Vorhersage falsch ist, ist die Behauptung fehlgeschlagen und Sie wissen, dass etwas schiefgegangen ist.

    Um Assertionen auszuführen, sollten Sie sie in einen Testfall einfügen:

     // Testen wir diese Funktion function isEven (val) return val% 2 === 0;  test ('isEven ()', function () ok (isEven (0), 'Null ist eine gerade Zahl'); ok (isEven (2), 'So ist zwei'); ok (isEven (-4) , 'Ist also negativ vier'); ok (! IsEven (1), 'Eins ist keine gerade Zahl'); ok (! IsEven (-7), 'Weder ist negativ sieben');)

    Hier haben wir eine Funktion definiert, isEven, die erkennt, ob eine Zahl gerade ist, und wir möchten diese Funktion testen, um sicherzustellen, dass sie keine falschen Antworten liefert.

    Wir rufen zuerst test () auf, wodurch ein Testfall erstellt wird. Der erste Parameter ist eine Zeichenfolge, die im Ergebnis angezeigt wird, und der zweite Parameter ist eine Rückruffunktion, die unsere Assertions enthält. Diese Callback-Funktion wird aufgerufen, sobald QUnit ausgeführt wird.

    Wir haben fünf Behauptungen geschrieben, die alle boolesch sind. Eine boolesche Zusicherung erwartet, dass der erste Parameter wahr ist. Der zweite Parameter ist auch eine Nachricht, die im Ergebnis angezeigt wird.

    Wenn Sie den Test ausführen, erhalten Sie Folgendes:

    Da alle diese Behauptungen erfolgreich bestanden wurden, können wir uns ziemlich sicher sein isEven () wird wie erwartet funktionieren.

    Mal sehen, was passiert, wenn eine Behauptung fehlgeschlagen ist.

     // Testen wir diese Funktion function isEven (val) return val% 2 === 0;  test ('isEven ()', function () ok (isEven (0), 'Null ist eine gerade Zahl'); ok (isEven (2), 'So ist zwei'); ok (isEven (-4) , 'Ist also negativ vier'); ok (! IsEven (1), 'eine ist keine gerade Zahl'); ok (! IsEven (-7), 'keine negative sieben'); (3), 'Drei ist eine gerade Zahl');)

    Hier ist das Ergebnis:

    Die Behauptung ist fehlgeschlagen, weil wir sie absichtlich falsch geschrieben haben. Wenn der Test in Ihrem eigenen Projekt jedoch nicht erfolgreich ist und alle Behauptungen korrekt sind, wissen Sie, dass ein Fehler gefunden wurde.

    Weitere Assertions

    ok () ist nicht die einzige Behauptung, die QUnit liefert. Es gibt andere Arten von Zusicherungen, die beim Testen Ihres Projekts hilfreich sind:

    Vergleich Assertion

    Die Vergleichsassertion, equals (), erwartet, dass der erste Parameter (der tatsächliche Wert ist) gleich dem zweiten Parameter (der erwartete Wert) ist. Es ist ähnlich wie in ok (), gibt jedoch sowohl tatsächliche als auch erwartete Werte aus, wodurch das Debuggen erheblich vereinfacht wird. Wie ok () wird zur Anzeige ein optionaler dritter Parameter benötigt.

    Also statt:

     test ('assertions', function () ok (1 == 1, 'eins ist eins');)

    Sie sollten schreiben:

     test ('assertions', function () entspricht (1, 1, 'eins entspricht eins');)

    Beachten Sie die letzte "1", die den Vergleichswert darstellt.

    Und wenn die Werte nicht gleich sind:

     test ('assertions', function () entspricht (2, 1, 'eins entspricht eins');)

    Es gibt viel mehr Informationen und macht das Leben viel einfacher.

    Die Vergleichsassertion verwendet "==", um ihre Parameter zu vergleichen, sodass der Array- oder Objektvergleich nicht behandelt wird:

     test ('test', function () ist gleich (, , 'fällt aus, das sind verschiedene Objekte'); gleich (a: 1, a: 1, 'fällt'); gleich ([ ], [], 'fail, es gibt verschiedene Arrays'); equals ([1], [1], 'fail');)

    Um diese Art von Gleichheit zu testen, gibt QUnit eine andere Art der Behauptung an: identische Behauptung.

    Identische Behauptung

    Die identische Assertion, same (), erwartet dieselben Parameter wie equals (), aber es ist eine tiefgehende rekursive Vergleichsassertion, die nicht nur für primitive Typen, sondern auch für Arrays und Objekte funktioniert. Assertions werden im vorherigen Beispiel alle bestanden, wenn Sie sie in identische Assertions ändern:

     test ('test', function () same (, , 'durchläuft, Objekte haben den gleichen Inhalt'); gleich (a: 1, a: 1, 'durchläuft'); [], [], 'passt, Arrays haben den gleichen Inhalt'); gleich ([1], [1], 'passt');)

    Beachten Sie, dass same () '===' verwendet, um einen Vergleich durchzuführen, wenn dies möglich ist. Daher ist es hilfreich, wenn Sie spezielle Werte vergleichen:

     test ('test', function () ist gleich (0, falsch, 'wahr'); gleich (0, falsch, 'falsch'); ist gleich (null, undefiniert, 'wahr'); gleich (null, undefiniert, ' falsch ');)

    Strukturieren Sie Ihre Behauptungen

    Alle Zusicherungen in einem einzigen Testfall zusammenzufassen, ist eine wirklich schlechte Idee, da sie sehr schwer zu verwalten ist und kein sauberes Ergebnis liefert. Sie sollten sie strukturieren, in verschiedene Testfälle einordnen und jeweils eine einzelne Funktionalität anstreben.

    Sie können sogar Testfälle in verschiedenen Modulen organisieren, indem Sie die Modulfunktion aufrufen:

     Modul ('Modul A'); test ('ein Test', Funktion () ); test ('ein weiterer Test', function () ); Modul ('Modul B'); test ('ein Test', Funktion () ); test ('ein weiterer Test', function () );

    Asynchroner Test

    In den vorherigen Beispielen werden alle Assertions synchron aufgerufen, dh sie werden nacheinander ausgeführt. In der realen Welt gibt es auch viele asynchrone Funktionen wie ajax-Aufrufe oder Funktionen, die von setTimeout () und setInterval () aufgerufen werden. Wie können wir solche Funktionen testen? QUnit bietet einen speziellen Testfall namens "asynchroner Test" an, der ausschließlich für asynchrone Tests gedacht ist:

    Versuchen wir zuerst, es regelmäßig zu schreiben:

     test ('asynchroner Test', function () setTimeout (function () ok (true);, 100))

    Sehen? Es ist, als hätten wir keine Behauptung geschrieben. Dies liegt daran, dass die Assertion asynchron ausgeführt wurde. Zu diesem Zeitpunkt war der Testfall bereits abgeschlossen.

    Hier ist die richtige Version:

     test ('asynchroner Test', function () // Test zuerst anhalten) stop (); setTimeout (function () ok (true); // // Nach dem Aufruf der Assertion // den Test fortsetzen start (); , 100) )

    Hier verwenden wir stop (), um den Testfall anzuhalten, und nachdem die Assertion aufgerufen wurde, verwenden wir start (), um fortzufahren.

    Das Aufrufen von stop () unmittelbar nach dem Aufruf von test () ist durchaus üblich. QUnit stellt daher eine Verknüpfung bereit: asyncTest (). Sie können das vorherige Beispiel wie folgt umschreiben:

     asyncTest ('asynchroner Test', function () // Der Test wird automatisch angehalten. setTimeout (function () ok (true); // Nachdem die Assertion aufgerufen wurde, // führe den Test start ();, 100 aus ))

    Es gibt eine Sache, auf die Sie achten sollten: setTimeout () ruft immer die Rückruffunktion auf, aber was ist, wenn es eine benutzerdefinierte Funktion ist (z. B. ein Ajax-Aufruf)? Wie können Sie sicher sein, dass die Rückruffunktion aufgerufen wird? Wenn der Rückruf nicht aufgerufen wird, wird start () nicht aufgerufen, und der gesamte Unit-Test wird hängen bleiben:

    Also, was Sie tun:

     // Eine benutzerdefinierte Funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchroner Test', function () // Unterbrechen Sie den Test und schlagen Sie fehl, wenn start () nach einem Sekundenstopp nicht aufgerufen wird (1000); ajax (function () //… asynchronous assertions start ( );))

    Sie übergeben ein Timeout an stop (), das QUnit mitteilt: "Wenn start () nach diesem Timeout nicht aufgerufen wird, sollten Sie diesen Test nicht bestehen." Sie können sicher sein, dass der gesamte Test nicht hängen bleibt und Sie benachrichtigt werden, wenn etwas schief geht.

    Wie wäre es mit mehreren asynchronen Funktionen? Wo setzt du den Anfang ()? Sie setzen es in setTimeout ():

     // Eine benutzerdefinierte Funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchroner Test', Funktion () // Anhalten des Tests stoppen (); ajax (function () //… asynchrone Assertions) ajax (Funktion () //… asynchrone Assertions) setTimeout (Funktion () start ();, 2000);)

    Das Timeout sollte ausreichend lang sein, damit beide Callbacks aufgerufen werden können, bevor der Test fortgesetzt wird. Was aber, wenn einer der Rückrufe nicht angerufen wird? Wie kannst du das wissen? Hier kommt Expect () ins Spiel:

     // Eine benutzerdefinierte Funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchroner Test', function () // Unterbrechen Sie den Teststop (); // teilen Sie QUnit mit, dass drei Assertions erwartet werden (3); ajax (function () ok (true);) ajax (function () ok (true); ok (true);) setTimeout (function () start ();, 2000);)

    Sie geben eine zu erwartende Nummer () ein, um QUnit mitzuteilen, dass Sie erwarten, dass X viele Assertions ausführt. Wenn eine der Assertions nicht aufgerufen wird, stimmt die Nummer nicht überein und Sie werden benachrichtigt, dass ein Fehler aufgetreten ist.

    Es gibt auch eine Abkürzung für expect (): Sie übergeben die Nummer einfach als zweiten Parameter an test () oder asyncTest ():

     // Eine benutzerdefinierte Funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  // Erklären Sie QUnit, dass Sie drei Assertions erwarten, um test auszuführen ('asynchroner Test', 3, function () // Unterbrechen Sie den Teststop (); ajax (function () ok (true);) ajax (function.) () ok (true); ok (true);) setTimeout (function () start ();, 2000);)

    Fazit

    Das ist alles, was Sie wissen müssen, um mit QUnit zu beginnen. Unit-Tests sind eine hervorragende Methode, um Ihren Code vor der Veröffentlichung zu testen. Wenn Sie noch keine Komponententests geschrieben haben, können Sie loslegen! Danke fürs Lesen!

    • Folgen Sie uns auf Twitter oder abonnieren Sie den Nettuts + RSS-Feed für die besten Webentwicklungs-Tutorials im Web.