js testen. JavaScript-Wissenstest - Grundlagen

Ein Freund von mir hat einmal seine Verwunderung darüber geäußert, wie man mit JavaScript überhaupt seriöse Unternehmensprodukte schreiben kann, weil es keinen Compiler hat. Denn die entscheidende Rolle bei der Erstellung von qualitativ hochwertigem Code spielt keineswegs ein Compiler für eine Programmiersprache, sondern ein richtig gewählter und gut abgestimmter technischer Prozess zur Erstellung eines Softwaresystems.

Dieser Prozess sollte eine Reihe von Qualitäts- und Effizienzkontrollinstrumenten für den Programmierer beinhalten. Solche Tools können sein: Unit- und Integrationstests, kontinuierliche Integration (Continuous Integration, CI), Sammlung und Analyse verschiedener Metriken (z. B. sehr lange Methoden in nDepend), Prüfung auf Einhaltung der Anforderungen von JsLint, FxCop usw.

In diesem Artikel möchte ich Ihnen sagen, wie Sie automatische Einheiten- und Integrationstests Ihres Produkts in JavaScript richtig durchführen. Tatsächlich unterscheidet sich JavaScript in dieser Hinsicht nicht von Java oder C#.

Agil, TDD und BDD

Generell wird empfohlen, automatische Unit- und Integrationstests für die ausgeführte Funktionalität zu erstellen, um das Risiko von Regressionsfehlern bei zukünftigen Codeänderungen zu reduzieren. Im Fall von JavaScript können diese Tests es viel einfacher machen, zu überprüfen, ob das System in verschiedenen Browsern funktioniert, indem die Schritte automatisiert werden, um sicherzustellen, dass es funktioniert. Darüber hinaus kann das Schreiben eines Unit- oder Integrationstests für jeden geschlossenen Fehler im Produkt einen guten Dienst leisten.

Es gibt auch Programmiertechniken, bei denen Sie mit dem Codieren von Logik beginnen müssen, indem Sie einen Komponententest schreiben: Test-Driven Development (TDD) und Behavior-Driven Development (BDD). Sie werden häufig im agilen Prozess verwendet. Betrachten wir ihre Funktionen genauer.

Testgetriebene Entwicklung

Testgetriebene Entwicklung ist ein iterativer Codierungsprozess, der die folgenden vier Schritte wiederholt:

Schritt 1. Bevor Sie eine neue Logik hinzufügen, erstellen Sie einen Komponententest, um diese Logik zu testen.

Schritt 2. Führen Sie den Test durch und überzeugen Sie sich davon Nicht geht vorbei;

Schritt 3. Schreiben Sie den einfachsten Code, mit dem der Test bestanden wird;

Schritt 4. Bearbeiten Sie den Code gemäß den Qualitätsanforderungen, entfernen Sie doppelte Codes und stellen Sie sicher, dass der Test bestanden wird.

Ein Komponententest ist ein Code, der den Betrieb einer Komponente (eines Moduls) in einer isolierten Umgebung testet. Ein Integrationstest ist ein Code, der testet gemeinsame Arbeit mehrere Komponenten. Testdoubles werden verwendet, um ein Modul in einer isolierten Umgebung zu testen, wenn es von anderen Modulen abhängt.

Doppel testen

Die Einteilung der beim Unit-Test verwendeten Hilfsobjekte in Kategorien stammt aus dem Buch xUnit Test Patterns von Gerard Meszaros. Diese Kategorien werden gemeinsam als "Testdoppel" (Testdoppel) bezeichnet. Verdoppler sind von den folgenden Typen:

  • gefälscht;
  • Schnuller.

Stummel Ausgangswerte für die im Voraus festgelegt werden. Es wird verwendet, um die Schnittstelle einer abhängigen Komponente nachzuahmen.

Verspotten ist ein Hilfsobjekt Verhalten die im Voraus festgelegt wird. Es wird verwendet, um die Schnittstelle einer abhängigen Komponente nachzuahmen und zu testen, ob sie während des Tests korrekt verwendet wird.

Spion ist ein Hilfsobjekt zum Untersuchen von aufgerufenen Methoden und Parametern, die ihnen während des Tests übergeben werden.

Gefälscht ist ein Hilfsobjekt, das die Schnittstelle einer abhängigen Komponente in vereinfachter Form implementiert. Beispielsweise können Sie für Komponententests anstelle der relationalen Datenbank, die in der Produktionsversion des Produkts verwendet wird, eine In-Memory-Datenbank verwenden.

Schnuller ist ein Hilfsobjekt, dessen Angabe oder Übergabe von der Methodensignatur oder einem anderen Vertrag verlangt wird, aber der tatsächliche Wert wird nie verwendet.

Der Unterschied zwischen Stub und Mock besteht darin, wie die Testergebnisse verifiziert werden. Bei Stub wird der Zustand des Objekts am Ende des Tests geprüft. Bei Mock prüft der Test, ob das Objekt genau so verwendet wird, wie es bei der Registrierung beschrieben wurde. Einzelheiten finden sich in der Notiz Mocks Aren't Stubs von Martin Fowler, und ich werde hier nur ein Beispiel geben.

Stummel Verspotten
"Testverbindung sollte Abfrage starten": function () ( this.client.url = "/my/url"; sinon.stub(ajax, "poll").returns(()); this.client.connect(); sinon.assert.calledWith(ajax.poll, "/my/url"); ) "test connect should start polling": function () ( this.client.url = "/my/url"; var mock = sinon.mock(ajax) mock.expects("poll") .withArgs("/my/url ").returns(()); this.client.connect(); mock.verify(); )

Verhaltensgesteuerte Entwicklung

Iterativer Entwicklungsansatz Software durch die Umsetzung funktionaler Anforderungen - das ist der bereits bekannte Stil der ergebnisorientierten testgetriebenen Entwicklung. Die folgenden drei Schritte werden im BDD-Prozess nacheinander durchlaufen:

Schritt 1. Definition funktionaler Anforderungen an das implementierte Modul in Form von Tests;

Schritt 2. Modulkodierung;

Schritt 3. Überprüfen, ob alle Wünsche des Kunden oder Business Analysten () erfüllt sind, indem die Ergebnisse laufender Tests überprüft werden.

Beim Schreiben von Tests im BDD-Stil ist es sehr praktisch, Mock-Objekte zu verwenden, da sie die funktionalen Anforderungen an die Komponente perfekt widerspiegeln. Somit können Tests im BDD-Prozess als formalisierte Repräsentation der Aufgabenstellung dienen ( Benutzer Geschichte) in Begriffen Gedränge, wodurch Sie beim Schreiben von technischen Spezifikationen und Dokumentationen für das fertige Produkt Zeit sparen können.

Was sollte ein JavaScript Unit Testing Framework sein?

Ein vollständiges Tool zum Testen von JavaScript-Einheiten und -Integrationen sollte aus den folgenden Komponenten bestehen:

  • Assertionsbibliothek (eine Reihe von Methoden zum Überprüfen des Zustands der Komponente am Ende jedes Tests);
  • Mock-Bibliothek (ein Tool zum Generieren von Mock-Objekten und anderen „Zweitbesetzungen“);
  • Testläufer (Instrument Auto-Start Tests mit Unterstützung für die meisten Browser, einschließlich iOS- und Android-Browser);
  • Verbindungsblock zu gängigen Systemen der kontinuierlichen Integration (Continuous Integration).

JavaScript Unit Testing-Strategien

Heute gibt es drei Strategien für Unit-Tests von JavaScript-Code (weitere Einzelheiten finden Sie im dritten Kapitel von Christian Johansens Buch Test-Driven JavaScript Development):

  • im Browser testen;
  • kopflos testen;
  • Unterwegs testen JsTestDriver.

Beim In-Browser-Testing werden alle Unit- und Integrationstests von einer HTML-Seite aus ausgeführt, die der Entwickler selbst in den erforderlichen Browsern öffnet. Dieser Ansatz ist einfach und intuitiv. Der Nachteil besteht jedoch darin, dass es keine Möglichkeit bietet, solche Tests in Continuous Integration einzubeziehen. Auch das manuelle Starten einer HTML-Seite in zehn oder mehr Browsern und das ständige Drücken von „F5“ kann für einen Entwickler mühsam sein.

Headless Testing bedeutet, dass der gesamte JavaScript-Code auf einem Emulator getestet wird, der in Java, Ruby, JavaScript, C++ usw. geschrieben sein kann. Der mit Abstand bekannteste Emulator ist PhantomJS, ein webkit, gestartet von Befehlszeile. Zu den Vorteilen des Emulators gehört, dass er problemlos in Continuous Integration verwendet werden kann und dass Sie den Start aller Tests von der Befehlszeile aus automatisieren können. Dieser Ansatz hat jedoch einen erheblichen Nachteil: Der Code wird nicht auf echten Browsern getestet, sodass die Gefahr besteht, dass Browserfehler fehlen, die auf dem Emulator nicht reproduziert werden. Vor dem Aufkommen von JsTestDriver konnte man häufig In-Browser-Tests in Kombination mit Headless-Tests sehen, da sie sich so gut ergänzen.

Testen ist ein integraler Bestandteil des Softwareentwicklungszyklus. Angehende Entwicklungsteams unterschätzen oft ihre Rolle und überprüfen die Leistung der Anwendung auf altmodische Weise – „es funktioniert, und das ist in Ordnung“. Früher oder später scheitert diese Strategie und der Bugtracker beginnt, die unzähligen Aufgabenarmeen zu überwältigen. Um nicht in eine solche Falle zu tappen, empfehle ich, sich ein für alle Mal mit den Nuancen des Testens von JavaScript-Code auseinanderzusetzen.

JavaScript ist kein Kuchen mehr!

Dass JavaScript heute nicht nur eine Sprache ist, um Dinge aufzupeppen, brauche ich Ihnen wohl nicht zu erklären. Aussehen Anwendungen. Aber ich erkläre es trotzdem und mache eine kleine Einführung, denn dann werde ich mehr bezahlt mehr Geld! 🙂 Die Zeiten, in denen JavaScript für Witze oder das Erstellen von Menüs verwendet wurde, sind also für immer vorbei. Jetzt ist es eine unabhängige Sprache, die sowohl auf dem Client als auch auf dem Server gleichermaßen gut funktioniert. Die Rolle von JavaScript hat stark zugenommen, was bedeutet, dass Sie sich beim Schreiben von Code nicht davor scheuen sollten, auf Praktiken zurückzugreifen, die sich in anderen Programmiersprachen bewährt haben.

Was meine ich mit Praktiken und Paradigmen? Natürlich das Architekturmuster MVC (Model View Controller) und Code-Organisationsmuster. Wenn Sie diese einfachen Tricks befolgen, können Sie besseren Code schreiben, der nicht nur einfach zu warten ist, sondern auch automatisch getestet werden kann.

Regeln für gute Prüfungen

  • Der Test sollte so einfach wie möglich sein. Je schwieriger der Test, desto wahrscheinlicher sind Fehler.
  • Tests sollten in Module gruppiert werden, damit es später einfacher ist, Fehler zu finden und bestimmte Teile der Anwendung testen zu können.
  • Jeder Test sollte nicht von anderen Tests abhängen.
  • Schreiben Sie immer einen separaten Test, wenn Sie einen Fehler finden.

Der Fehler der meisten Tester

Es ist kein Geheimnis, dass die beliebteste Testmethode schon immer ein banaler Sehtest war. Seine Essenz ist einfach zu blamieren - ich habe ein paar tausend Codezeilen geschrieben, das Problem gelöst und meine Kreation gestartet. Ich habe herumgespielt, geklickt - alles scheint zu funktionieren, Sie können es auf den Kampfserver hochladen. Alles ist extrem einfach, und mit der gebührenden Aufmerksamkeit des Entwicklers (idealerweise ein einzelner Spitzname "Tester") können Sie sich auf den korrekten Betrieb der Anwendung verlassen.

In der Praxis läuft alles etwas anders ab. In der Regel gibt es keinen separaten Tester. Der Entwickler selbst versucht, die Funktionsfähigkeit des Programms zu überprüfen, indem er die in der technischen Aufgabe angegebene Aktionsfolge ausführt. Fortgeschrittenere Codeschmieden automatisieren diese Art von Integrationstests mit Tools wie Selenium .

Somit erhält der Programmierer die Möglichkeit, nur die gröbsten Fehler zu entdecken. Leider bleiben "dumme" und "unvorhergesehene" Benutzeraktionen sowie knifflige Schritte in der Geschäftslogik in 99% der Fälle hinter den Kulissen.

Auch das Vorhandensein eines separaten Testers löst das Problem teilweise und bis zu einem gewissen Zeitpunkt. Selbst wenn wir seine Pionierliebe zum Detail verwerfen, wird die Qualität seiner Tests mit zunehmender Anwendung gegen Null gehen. Ich nenne ein Beispiel aus der Praxis.

Einmal wurde ich beauftragt, ein kleines Programm zu entwickeln. Von der Funktionalität her glich das Projekt dem einfachsten CRM, das ich in kürzester Zeit implementiert habe. Nachdem ich die fällige Vergütung erhalten hatte, übergab ich dem Kunden alle Quellen und vergaß das Projekt für acht Monate. Dann begann das Interessanteste. Der Kunde beschloss, die Funktionalität des Programms ernsthaft zu erweitern, und rief mich um Hilfe an. Natürlich nahm ich es und fing an, Funktion für Funktion zu modellieren ... Anfangs war es nicht schwierig, aber als es um die Gesamtintegration der Funktionalität ging, stürmte ein schwirrender Schwarm von Bugs in meine Richtung. Codeteile begannen zu widersprechen, und ich musste viel Zeit damit verbringen, Konflikte zu lösen. „Nun, wieso hast du nicht gesehen, dass es ein Problem mit deiner Bewerbung gibt?“ Leser werden fragen. Ich werde antworten: Ich habe es gestartet, aber aufgrund der Tatsache, dass die Anwendung gewachsen ist, hatte ich einfach nicht die Zeit und die Nerven, alle Funktionen massenhaft zu testen. Ich habe mich darauf beschränkt, nur einzelne Funktionen zu testen und großzügig dafür bezahlt. Moral der Geschichte: „Betrachten Sie das Testen als integralen Bestandteil der Entwicklung.“

Unit-Tests sind wie eine Wunderwaffe

Unit-Tests sind der beste Weg, um Ihre Nerven zu schonen und die Garantien zu erhöhen, dass einzelne Teile Ihrer Anwendung funktionieren. Wenn Sie diesem schrecklichen Biest noch nie begegnet sind, werde ich es kurz erklären. Unit-Tests ermöglichen es Ihnen, den Testprozess zu automatisieren und jede Funktion Ihrer Anwendung Tests auszusetzen.

Nach Abschluss der Entwicklung neue Funktion(es ist möglich, Tests vor Beginn der Entwicklung zu schreiben) Der Entwickler schreibt einen speziellen Code, um seinen Code zu testen. Es muss verschiedene Situationen simulieren und Werte zurückgeben. Zum Beispiel haben wir eine Funktion geschrieben, um Leerzeichen zu kürzen (trimmen). Um seine Leistung zu testen, müssen wir mehrere Tests vorbereiten, die es uns ermöglichen, Folgendes zu behaupten:

  • beim Übergeben des Strings "string" erhalten wir "string" als Ausgabe;
  • beim Übergeben der Terme "line 9" am Ausgang erhalten wir "line 9";

Wir können auch Tests für andere Eingabeparameter hinzufügen (z. B. das Leerzeichen durch einen Tabulator ersetzen). Generell gilt: Je besser wir den Code mit Tests abdecken und je mehr wir mögliche negative Optionen vorhersehen, desto höher sind die Chancen, dass im entscheidenden Moment ein kleines Haar auf dem Kopf bleibt.

In der JS-Welt werden Tests normalerweise mit spezialisierten Frameworks geschrieben. Sie haben alles, was Sie dafür brauchen, sowie einige Tools zum Organisieren von Testfortschrittsberichten.

Tests!= Zusatzcode

Nicht-Unit-Tester argumentieren gerne, dass Unit-Tests geschrieben und gepflegt werden müssen zusätzlicher Code. Sie sagen, dass die Fristen in echten Projekten meistens komprimiert sind und es einfach nicht möglich ist, zusätzlichen Code zu schreiben.

Wenn keine Zeit für Tests bleibt

Mangels Zeit macht es keinen Sinn, Tests für einfache Funktionen zu schreiben (nehmen Sie dasselbe trim () aus dem Beispiel im Artikel), es ist besser, sich auf die kritischsten Abschnitte des Codes zu konzentrieren. Die gleiche Regel sollte befolgt werden, wenn häufig geänderter Code geschrieben wird. Die Aufgabenstellung eines Live-Projekts ändert sich oft, und einige Funktionen müssen ständig aktualisiert werden. Solche Änderungen können zu unangenehmen Momenten führen - der geänderte Code funktioniert gut mit neuen Daten, verdaut die alten jedoch nicht organisch. Um hier keinen Fehler zu erwischen, ist es besser, solche Funktionen sofort zu überprüfen. Denken Sie an eine einfache Regel: Es ist keine Zeit, den gesamten Code mit Tests abzudecken – decken Sie den wichtigsten Teil davon ab.


Was die engen Fristen betrifft, stimme ich zu, aber ich bin bereit, über den Teil des Zusatzcodes zu streiten. Auf der einen Seite ja - Tests erfordern zusätzlichen Code und damit die Zeit, ihn zu schreiben. Andererseits spielt dieser Code die Rolle von Airbags in einem Auto und wird sich mit wachsender Anwendung definitiv auszahlen.
  • Cristian Johansen Test-Driven JavaScript Development (goo.gl/mE6Is) ist eines der wenigen Bücher, das sich mit JavaScript aus der Perspektive des Testschreibens befasst.
  • John Resing, Beer Bibo JavaScript Ninja Secrets (goo.gl/xquDkJ) ist ein gutes Buch, das hauptsächlich für fortgeschrittene JS-Entwickler nützlich sein wird. Das Buch behandelt ausführlich die Probleme beim Schreiben von effektivem Cross-Browser-Code, die Nuancen der Ereignisbehandlung und viele andere Leckereien.
  • David Flanagan JavaScript. Vollständiger Leitfaden» (goo.gl/rZjjk) - Das Buch wurde sechsmal neu aufgelegt und jede Veröffentlichung ist ein Bestseller. In der Tat ist dies das meiste ausführliche Anleitung zu JavaScript, die jeder JS-Entwickler mindestens einmal gelesen haben muss.
  • PhantomJS + JSCoverage + QUnit oder Konsolen-JS-Einheitentests mit Abdeckungsberechnung (goo.gl/FyQ38) – der Autor des Artikels demonstriert die Verwendung einer Reihe der oben genannten Pakete, um Statistiken zu sammeln und den Prozentsatz der Codeabdeckung durch Tests zu berechnen.
  • Nützliche PhantomJS-Anwendungsfälle – Diese Seite zeigt eine große Anzahl von PhantomJS-Kampfanwendungen.

Wenn keine Zeit ist und der Wunsch, das Schreiben von Tests abzulehnen, quälend ist, denken Sie dreimal nach. Vielleicht wäre es in diesem Fall angemessener, nur die kniffligsten Teile des Codes mit Tests abzudecken, anstatt das Testen ganz aufzugeben. Denken Sie immer vorausschauend, als ob Ihr Programm in einem Monat zu einer noch nie dagewesenen Größe anwachsen könnte.

Nicht der gesamte Code wird getestet

Warum sage ich, dass Sie über das Testen nachdenken müssen, bevor Sie den Hauptcode schreiben? Ja, denn der Code, der zunächst durch Unit-Tests abgedeckt werden soll, ist in einem etwas anderen Stil geschrieben. Nicht jeder Code kann getestet werden. Code, der Logik und Repräsentationen vermischt und sogar vollgestopft ist, ich verstehe nicht wo, kann nicht normal getestet werden. Hier rate ich dir immer, ein paar einfache Regeln zu beachten:

  • Keine Notwendigkeit, große Funktionen zu schreiben. Jede Funktion soll ein Problem lösen, nicht 100500 mögliche Situationen. Sie müssen beispielsweise den Code zum Senden von Daten an den Server nicht in der Funktion aufhängen, die für deren Aufbereitung zuständig ist.
  • Eine Funktion mit mehr als zehn Codezeilen ist höchstwahrscheinlich eine schlechte Funktion.
  • Logik und Präsentation sollten niemals zusammenpassen.

QUnit - ein Klassiker des Genres von den Machern von jQuery

QUnit ist besonders beliebt bei JavaScript-Entwicklern. Erstens ist es gut dokumentiert und einfach zu verwenden, und zweitens wurde es von den jQuery-Autoren erstellt. Die Bibliothek eignet sich sowohl zum Testen von jQuery-basiertem als auch nativem JavaScript-Code.


Herunterladen letzte Version QUnit können Sie von der offiziellen Seite . Die Bibliothek wird als einzelne JS- und CSS-Datei geliefert. Nehmen wir an, Sie haben herausgefunden, wie die erforderlichen Komponenten geladen werden, und wenn dies der Fall ist, ist es an der Zeit, einen Test zu schreiben. Lassen Sie uns nicht weit gehen und versuchen, die Funktion trim() zu testen.

Um die Tests zu demonstrieren, habe ich ein einfaches Projekt mit der folgenden Struktur erstellt:

  • index.html - die Hauptdatei, die die Testergebnisse anzeigt;
  • qunit-1.12.0.js - QUnit-Bibliotheksdatei;
  • example.js – eine Datei, die den Testcode enthält (in unserem Fall die Beschreibung der Funktion trim());
  • test.js - Datei mit Tests;
  • qunit-1.12.0.css - Stile zum Entwerfen eines Berichts mit Tests.

Die Inhalte der Dateien index.html und test.js sind in den Listings 1 und 2 dargestellt. Das zweite Listing, das uns am meisten interessiert, ist die Deklaration der zu testenden Funktion (trim()) und der Testcode, um zu überprüfen, ob sie funktioniert . Bitte beachten Sie, dass sich die Funktion trim() selbst überall befinden kann, ich habe sie in die zweite Auflistung eingefügt, nur um Platz im Protokoll zu sparen.
Schauen wir uns nun die Tests selbst an. Die QUnit.js-Bibliothek bietet uns eine Reihe von Methoden:

  • test() - Wrapper für Testbeschreibung;
  • ok() - Assertion ermöglicht es Ihnen, die Wahrheit des ersten Parameters zu überprüfen. In unserem Beispiel übergebe ich einen Aufruf an die von uns definierte Funktion trim() und vergleiche sie mit dem erwarteten Wert. Wenn die Bedingung wahr ist, ist der Test bestanden;
  • equal() - Mit dieser Methode können Sie die Gleichheit des ersten und des zweiten Parameters überprüfen. Merken Sie sich das gleich diese Methode führt eine nicht strenge Prüfung durch, ist also nur für Skalare geeignet;
  • notEqual() ist das Gegenteil von equal(). Wird ausgeführt, wenn der erste Wert ungleich dem zweiten ist;
  • strictEqual() - ähnlich wie equal() mit einem Unterschied - es verwendet eine strenge Prüfung (das heißt, es prüft auch den Datentyp);
  • notStrictEqual() - das Gegenteil von strictEqual();
  • deepEqual() - Methode für rekursive Anweisungen, verwendet für Primitive, Arrays, Objekte;
  • notDeepEqual() - das Gegenteil von deepEqual();
  • raises() ist eine Assertion zum Testen von Callback-Funktionen, die eine Ausnahme auslösen.

Im zweiten Listing habe ich anschaulich gezeigt, wie man diese Methoden in der Praxis anwendet. Wenn Sie in dieser Form einen Testfall ausführen, werden alle Tests erfolgreich bestanden (siehe entsprechende Abbildung). Um den Unterschied zwischen bestandenen und nicht bestandenen Tests zu sehen, habe ich den Code eines Tests leicht geändert. Ich habe die Zeile mit dem Test absichtlich mit strictEqual() um ein fehlerhaftes Ergebnis ergänzt (siehe entsprechende Abbildung).

Listing 1. Inhalt der Datei index.html Testen mit QUnit



Beim Testen einfacher Funktionen scheint es verständlich. Jedenfalls habe ich nichts mehr hinzuzufügen. Dann müssen Sie den echten Code nehmen und versuchen, selbst Tests zu schreiben. Schauen wir uns eine weitere häufig anzutreffende Aufgabe für JavaScript-Entwickler an – das Testen asynchroner Funktionen. Eine mit JavaScript-Code gefüllte Anwendung interagiert zu 99 % mit der Serverseite, die AJAX verwendet. Es ist auch unmöglich, diesen Code ohne Tests zu belassen, aber das Schreiben von Tests sieht etwas anders aus. Betrachten Sie ein Beispiel:

AsyncTest("myAsyncFunc()", function () ( setTimeout(function () ( ok(myAsyncFunc() == true, "Daten erfolgreich übergeben"); start(); , 500); ));

Der Hauptunterschied zwischen diesem Beispiel und dem vorherigen besteht darin, dass asyncTest() anstelle des test()-Wrappers verwendet wird, was direkt zum Ausdruck bringt, dass ich an asynchronen Tests interessiert bin. Als nächstes starte ich ein Timeout von 500 Millisekunden. Während dieser Zeit sollte die Funktion myAsyncFunc() Daten an den Testserver übertragen und, wenn alles in Ordnung ist, true zurückgeben. Hier kommt der interessanteste Moment. Wenn asyncTest() aufgerufen wird, wird der Ausführungs-Thread gestoppt, und wenn der Test beendet ist, muss er selbst gestartet werden. Um den Ablauf der Ausführung zu steuern, stellt QUnit die Methoden start() und stop() bereit.


Das Testen asynchroner Funktionen mit der QUnit-Bibliothek ist ziemlich einfach. Das letzte Beispiel, das ich mir ansehen möchte, ist das Schreiben eines Tests, der mehrere asynchrone Prüfungen durchführt. Die Hauptfrage, die sich bei solchen Aufgaben stellt, ist der optimale Ort, um den Thread der Ausführung zu beginnen. Das offizielle Dokument schlägt vor, so etwas zu verwenden

AsyncTest("myAsyncFunc()", function () ( Expect(3); // Hier drei Tests durchführen ok(myAsyncFunc(), "Die Welt besser machen 1"); ok(myAsyncFunc(), "Die Welt besser machen 2 ") ; ok(myAsyncFunc(), "Die Welt zu einem besseren Ort machen 3"); setTimeout(function () ( start(); ), 3000); ));

Testen Sie auf benutzerdefinierte Aktionen

Sie sollten immer daran denken, dass viele Schnittstellen-Dinge aller Art in JavaScript geschrieben sind. Zum Beispiel klickt ein Benutzer auf einen Zuhälter und als Reaktion auf seinen Klick sollte etwas passieren. In Projekten gibt es eine Unmenge an solchem ​​„Schnittstellen“-Code, der auch mit Tests abgedeckt werden muss. Sehen wir uns an, wie wir einen Tastendruck des Benutzers simulieren können, und schreiben Sie einen separaten Test für diese Aktion. Stellen wir uns vor, dass wir eine Funktion haben, die die gedrückten Tasten protokolliert. Ich habe ihren Code in der dritten Auflistung angegeben.

Listing 3. Tastenanschläge protokollieren Funktion KeyLogger(target) ( if (!(this instanceof KeyLogger)) ( return new KeyLogger(target); ) this.target = target; this.log = ; var self = this; this.target. off ("keydown").on("keydown", function(event) ( self.log.push(event.keyCode); )); )

Lassen Sie uns nun diese Funktion zum Testen ausprobieren. Zunächst müssen wir im Hauptteil des Tests die gedrückte Taste emulieren. Am einfachsten geht dies mit der jQuery-Bibliothek, mit der Sie in wenigen Codezeilen ein Ereignis erstellen können (siehe Listing 4).

Listing 4. Testcode für KeyLogger test("Key recording test", function () ( var event, $doc = $(document), keys = KeyLogger($doc); event = $.Event("keydown"); event .keyCode = 9; $doc.trigger(event); equal(keys.log.length, 1, „Taste protokolliert“); equal(keys.log, 9, „Taste gedrückt mit Code 9 protokolliert“); ));

Ganz am Anfang der Auflistung mit dem Test bereite ich ein Ereignis vor, um einen Tastendruck zu emulieren - "keydown". Wir werden daran interessiert sein, die Tabulatortaste (Code 9) zu drücken. Dann sende ich mit der Methode trigger() das vorbereitete Event, wonach ich mit dem Testen beginnen kann. Zuerst prüfen wir das Gesamtbild – ob eine Taste gedrückt wurde, und dann deren Code.

DOM unter dem Deckmantel von Tests

Da Sie mit Qunit.js benutzerdefinierte Aktionen testen können, sollte auch das Schreiben von Tests für das DOM kein Problem darstellen. Das ist wahr, und das folgende Beispiel wird meine Worte bestätigen. Ich werde es nicht kommentieren, schau dir einfach den Code an und alles wird klar:

Test("Hinzufügen eines neuen div-Elements", function () ( var $fixture = $("#qunit-fixture"); $fixture.append("

Das ist die neue div
"); equal($("div", $fixture).length, 1, "Neues div erfolgreich hinzugefügt!"); ));

PhantomJS - Führen Sie Tests von der Konsole aus aus


Das Schreiben von Tests mit der QUnit.js-Bibliothek ist bequem und einfach, aber früher oder später werden Sie von dem Wunsch heimgesucht, den Start, das Testen und das Sammeln von Ergebnissen irgendwie zu automatisieren. Zum Beispiel habe ich für dieses Unternehmen eine separate virtuelle Maschine in DigitalOcean, die ich nur über die Konsole verwalten kann.

Das PhantomJS-Projekt löst dieses Problem elegant genug. Dies ist nicht nur ein weiteres Framework zum Schreiben von Komponententests, sondern eine vollwertige Konsolenversion der WebKit-Engine. Einfach ausgedrückt emuliert diese Anwendung einen Browser. Mit Hilfe von PhantomJS geht es nicht nur darum, die Überprüfung der Testausführung zu automatisieren, sondern auch viele Aufgaben zu lösen, die früher oder später vor einem Entwickler stehen: die Ergebnisse des Renderns von Seiten in eine Datei (PNG, JPG) bringen, Netzwerküberwachungsfunktionen (Ladegeschwindigkeit, Gesamtleistung usw.), Emulation von Benutzeraktionen und so weiter. Ich empfehle, nicht faul zu sein und die offizielle Dokumentation zu diesem Projekt zu lesen, Sie werden auf jeden Fall etwas Interessantes für sich finden.

PhantomJS kann für verschiedene Plattformen kompiliert werden (*nix, OS X, Windows). Wenn Sie alles unter Windows entwickeln, gibt es keine Probleme - führen Sie die Binärdateien zusammen und fahren Sie fort. Kleinere Startschwierigkeiten können auftreten, wenn Sie zwei Videoadapter installiert haben, von denen einer NVIDIA ist. In diesem Fall müssen Sie den in der Seitenleiste beschriebenen Hack verwenden.


Lassen Sie uns versuchen, PhantomJS in der Praxis kennenzulernen. Um die im letzten Abschnitt vorbereiteten Tests durch PhantomJS laufen zu lassen und die Ergebnisse der Ausführung in der Konsole abzurufen, benötigen wir ein spezielles Ladeskript – run-qunit.js . Öffnen Sie die Konsole (ich arbeite unter Windows, also verwende ich cmd) und geben Sie den Befehl im Format ein

phantom.exe<путь к run-qunit.js> <путь к странице с тестами>

In meinem Fall sah der Startbefehl so aus:

E:\soft\phantomjs>phantomjs.exe E:\temp\testjsforx\qunit\run-qunit.js file:///E: /temp/testjsforx/qunit/index.html

Das Ergebnis seiner Ausführung:

Tests in 2592 Millisekunden abgeschlossen. 9 Behauptungen von 9 bestanden, 0 nicht bestanden.

Alle Tests bestanden

Es ist auf jeden Fall notwendig, den Code mit Tests abzudecken, und es spielt keine Rolle, in welchem ​​Umfang Sie die Anwendung erstellen. Ich erinnere Sie noch einmal daran: Auch die kleinsten Programme werden zu plumpen Monstern, die unterstützt und mit Funktionalität ergänzt werden müssen. Gut getesteter Code ist der Schlüssel zu Erfolg und Qualität. Ja, es ist nicht einfach, sofort mit dem Schreiben von Code zu beginnen, der für automatisierte Tests geeignet ist, aber glauben Sie mir, all diese Qualen werden sich in Zukunft mehr als auszahlen. Das war's für heute, viel Glück!

PhantomJS-Probleme unter Windows

Es ist einfach so passiert, aber ich habe alle Beispiele für diesen Artikel nicht unter Linux getestet, sondern unter dem guten alten Windows 7. Es stellt sich heraus, dass PhantomJS einige Probleme hat, wenn es um Systeme geht, die mehrere Grafikkarten verwenden. Auf meinem Laptop hängt neben dem integrierten Videochip auch NVIDIA, und aus diesem Grund weigerte sich PhantomJS kategorisch, auf den Befehl phantom.exit () zu reagieren. Infolgedessen beendete der PhantomJS-Prozess nach Ausführung des Skripts seine Arbeit nicht und blieb weiterhin im Speicher hängen. Das Terminalfenster reagierte auch nicht mehr auf Exit-Befehle ( hat nicht geholfen).

Wenn Sie mit einem ähnlichen Problem konfrontiert sind und PhantomJS unter Windows verwenden möchten, machen Sie sich bereit für den folgenden Hack. offene Tafel NVIDIA-Steuerung. Suchen Sie das Element "3D-Einstellungen" in der Baumstruktur. Auf der rechten Seite ist die Option „Bevorzugt Grafikadapter". Standardmäßig. sein Wert ist auf Autoselect gesetzt. Wir müssen es in „Hochleistungs-NVIDIA-Prozessor“ oder „Integrierte Grafikhardware“ ändern. Nach diesem einfachen Trick begann sich PhantomJS gehorsam zu verhalten.

Das Erstellen effektiver Testfälle kann entscheidend sein Hauptprojekte, falls sich das Verhalten von Teilen der Anwendung aus verschiedenen Gründen ändern kann. Das vielleicht häufigste Problem tritt auf, wenn eine große Gruppe von Entwicklern an denselben oder verwandten Modulen arbeitet. Dies kann zu einer ungeplanten Änderung des Verhaltens von Funktionen führen, die von anderen Programmierern geschrieben wurden. Oder das Arbeiten unter engen Fristen führt zu einer versehentlichen Änderung kritischer Teile der Anwendung.

Das Testen einer Webanwendung besteht normalerweise aus einer visuellen Bewertung der Seitenelemente und einer empirischen Bewertung der Leistung der Funktionalität. Mit anderen Worten, beim Navigieren durch Abschnitte und beim Ausführen von Aktionen an dynamischen Elementen.

Im Laufe der Zeit wird das Projekt mit neuen gefüllt Funktionalität, was den Prozess der Überprüfung seiner Arbeit verlängert und erschwert. Unit-Tests werden zur Automatisierung verwendet.

Es gibt 2 Ansätze zum Erstellen von Testszenarien:

  • weiße Kistetesten– Das Schreiben von Tests basiert auf der Implementierung der Funktionalität. Diese. Wir suchen nach denselben Algorithmen, auf denen die Arbeit der Module unseres Systems basiert. Dieser Ansatz garantiert nicht den korrekten Betrieb des Systems als Ganzes.
  • Flugschreibertesten– Scripting basiert auf Spezifikationen und Systemvoraussetzungen. Auf diese Weise können Sie die Korrektheit der Ergebnisse der gesamten Anwendung überprüfen, aber dieser Ansatz erlaubt es Ihnen nicht, kleine und seltene Fehler zu erkennen.

Was testen

Es scheint eine gute Idee zu sein, jedes Feature, das Sie implementieren, zu testen. Dies ist nicht ganz richtig. Das Schreiben von Tests nimmt die Zeit eines Entwicklers in Anspruch. Um den Prozess der Arbeit an der Erstellung einer Anwendung zu optimieren, lohnt es sich, Tests nur für komplexe, kritische oder solche Funktionen vorzubereiten, die von den Ergebnissen anderer Systemmodule abhängen. Decken Sie Tests mit mehrdeutiger Logik ab, die möglicherweise Fehler enthalten könnten. Es lohnt sich auch, Tests für die Teile des Codes zu erstellen, die in Zukunft optimiert werden sollen, damit Sie nach dem Optimierungsprozess sicherstellen können, dass sie korrekt ausgeführt werden.

Im Allgemeinen ist es äußerst wichtig, die Testkosten gegen die Knappheit der Entwicklungszeit abzuwägen. Wenn Sie zeitlich nicht begrenzt sind, können Sie natürlich jede Funktion durch Tests abdecken lassen. Da die Entwicklung in der Regel jedoch unter engem Zeitdruck erfolgt, besteht die Aufgabe eines Analysten oder eines erfahrenen Entwicklers darin, zu verstehen, wo Testbedarf besteht. Darüber hinaus erhöht das Schreiben von Tests die Kosten des Projekts.

Somit können wir 3 Fälle formulieren, in denen der Einsatz von Unit-Tests gerechtfertigt ist:

1) Wenn die Tests es ermöglichen, Fehler schneller zu identifizieren als mit ihrer üblichen Suche.

2) Reduzieren Sie die Debugging-Zeit

3) Sie können häufig geänderten Code testen.

Von den 3 Hauptkomponenten des Frontends (HTML, CSS, JavaScript) muss vielleicht nur der JavaScript-Code getestet werden. CSS wird nur visuell validiert, wenn der Entwickler/Tester/Kunde es sieht GUI in diversen Browsern. HTML - Markup wird nach der gleichen Methode geprüft.

Wie man testet

Beim Entwerfen von Testszenarien sollten Sie sich an folgenden Grundsätzen orientieren:

  • Ihre Tests sollten so einfach wie möglich sein. Dann ist es wahrscheinlicher, dass der Fehler, den Sie zu wiederholen versuchen, die Ergebnisse seiner Implementierung beeinflusst.
  • Tests großer Module zerlegen. Grove, um die spezifische Stelle des Fehlers zu finden.
  • Machen Sie Tests unabhängig. Das Ergebnis eines Tests sollte auf keinen Fall von den Ergebnissen eines anderen abhängen.
  • Die Testergebnisse sollten vollständig wiederholbar und erwartet sein. Jedes Mal, wenn Sie den Test erneut ausführen, sollte das Ergebnis dasselbe sein wie beim letzten Mal.
  • Für jeden Fehler bei der Ausführung der Anwendung muss ein Testskript erstellt werden. Auf diese Weise stellen Sie sicher, dass der Fehler wirklich behoben ist und den Benutzern nicht angezeigt wird.

Wie man testet

Es gibt mehrere Bibliotheken für Unit-Tests von js-Code. Am gebräuchlichsten ist vielleicht QUnit. Um Komponententests mit dieser Bibliothek durchzuführen, müssen wir eine „Sandbox“ erstellen – eine einfache HTML-Seite, in der die Testbibliothek, der zu testende Code und die Tests selbst verbunden werden.

Funktionen für Tests:

(function() ( window.stepen = function(int) ( var result = 2; for (var i = 1; i< int; i ++) { result = result * 2; } return result; } window.returnFunc = function() { return "ok"; } })();

Testliste:

Test("stepen()", function() ( equal(stepen(2), 4, "2^2 - equal method"); ok(stepen(3) === 8, "2^3 - ok method" ); deepEqual(stepen(5), 32, "2^5 - deepEqual-Methode"); )); asyncTest("returnFunc()", function() ( setTimeout(function() ( equal(returnFunc(), "ok", "Async Func Test"); start(); ), 1000); ));

Wie Sie sehen können, unterstützt QUnit 3 Funktionen zum Vergleichen der Ergebnisse der Codeausführung mit den erwarteten:

  • OK()- betrachtet den Test als erfolgreich, wenn das Rückgabeergebnis = wahr ist
  • gleich()- vergleicht das Ergebnis mit dem erwarteten
  • deepEqual()- vergleicht das Ergebnis mit dem erwarteten und überprüft seinen Typ

Ausführungsergebnis:

Wie Sie sehen können, testet die QUnit-Bibliothek den Code für mehrere Browser gleichzeitig.

Es gibt eine Reihe weiterer Bibliotheken für Komponententests. Das Konzept zum Erstellen von Testskripten in ihnen ist jedoch dasselbe, sodass es für Sie nicht schwierig sein wird, zu einem anderen zu wechseln, nachdem Sie sich mit einem befasst haben.

Wichtig zu merken

Ein Merkmal des modernen js-Codes ist die Asynchronität seiner Ausführung. Bibliotheken zum Testen haben normalerweise die Möglichkeit, asynchrone Tests durchzuführen. Wenn Sie jedoch beispielsweise versuchen, eine Funktion zu testen, die beispielsweise eine Get-Anforderung an das Backend sendet und eine Antwort von diesem zurückgibt, müssen Sie den Thread mit der Funktion stop() starten starten, um Tests durchzuführen die zu testende Funktion, und starten Sie dann den Thread mit der Methode start() neu und "verpacken" Sie ihn in setTimeout(). Diese. Sie müssen ein Zeitintervall festlegen, in dem die Ausführung der Funktion abgeschlossen sein soll. Man muss die Dauer dieses Segments, .k, sorgfältig wählen. Einerseits kann die lange Arbeit des Verfahrens entweder ein Merkmal oder sogar eine Notwendigkeit für eine bestimmte Implementierung der Anwendungsfunktionalität oder ein falsches Verhalten sein.

Testen von Backbone-Anwendungen

Als Beispiel für das Testen von Anwendungen, die mit Backbone.js geschrieben wurden, verwenden wir das in beschriebene Projekt.

Sie können mit Unit-Tests überprüfen:

  • Korrektheit der Erstellung von Modellen und Controllern
  • Korrektheit der Daten in Modellen
  • Ausführen von Controller-Methoden (dazu müssen sie ein Ergebnis zurückliefern)
  • Ladeerfolg anzeigen

Testcode:

Test("Backbone.js", function() ( ok(sample, "Namespace check"); ok(sample.routers.app, "Router check"); ok(sample.core.pageManager.open("chat") , "Seitenöffnungstest (Controller-Methodenaufruf)") ok(sample.core.state, "Model check"); equal(sample.core.state.get("content"), "sintel", "Model data get test "); stop(); ok(function() ( $.ajax(( url: "app/templates/about.tpl", dataType: "text" )).done(function(data) ( self.$el. html(data); return data; )) ), "Template loading check"); setTimeout(function() ( start(); ), 1000); ));

Das Ergebnis der Arbeit mit Testfehlern:

Automatisierung von Testläufen

Typischerweise ist das Bereitstellen einer Anwendung eine Aufgabe, die während intensiver Entwicklung ziemlich oft durchgeführt werden muss. Daher ist dieser Vorgang normalerweise automatisiert. Wir verwenden Jenkins, ein kontinuierliches Integrationstool, in unserer Arbeit. Die Idee ist, die Bereitstellung über Jenkins mit automatisierten Tests zu kombinieren.

QUnit-Tests werden im Browser ausgeführt. Phantomjs, eine Software, die den Browser emuliert, hilft uns, diese Funktion zu umgehen. Die phantomjs-Entwickler haben bereits ein Skript zum Ausführen von QUnit-Tests bereitgestellt, das jedoch noch leicht modifiziert werden musste, damit es korrekt funktioniert.

/** * Warten bis die Testbedingung wahr ist oder ein Timeout eintritt. * Nützlich zum Warten * auf eine Serverantwort oder auf eine UI-Änderung (FadeIn usw.). * * @param testFx Javascript-Bedingung, die als boolescher Wert ausgewertet wird, * sie kann als Zeichenfolge übergeben werden (z. B.: "1 == 1" oder * "$("#bar").is(":visible)" oder * als Callback-Funktion * @param onBereit, was zu tun ist, wenn die testFx-Bedingung erfüllt ist, * kann als String übergeben werden (z. B.: "1 == 1" oder * "$("#bar").is (":visible")" oder * als Callback-Funktion. * @param timeOutMillis die maximale Wartezeit. Wenn nicht * angegeben, werden 3 Sekunden verwendet. */ function waitFor(testFx, onReady, timeOutMillis) ( var maxtimeOutMillis = timeOutMillis - timeOutMillis: 3001, //< Default Max Timout is 3s start = new Date().getTime(), condition = false, interval = setInterval(function() { if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { // If not time-out yet and condition not yet fulfilled condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code } else { if(!condition) { // If condition still not fulfilled // (timeout but condition is "false") console.log(""waitFor()" timeout"); phantom.exit(1); } else { // Condition fulfilled (timeout and/or condition is //"true") console.log(""waitFor()" finished in " + (new Date().getTime() - start) + "ms."); typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it"s supposed to do once the // condition is fulfilled clearInterval(interval); //< Stop this interval } } }, 100); // repeat check every 250ms }; }; if (phantom.args.length === 0 || phantom.args.length >2) console.log("Verwendung: run-qunit.js URL"); phantom.exit(); ) var page = neue Webseite(); // „console.log()“-Aufrufe aus dem Page-Kontext // an den Phantom-Hauptkontext weiterleiten (d. h. aktuelles „this“) page.onConsoleMessage = function(msg) ( console.log(msg); ); page.open(phantom.args, function(status)( if (status !== "success") ( console.log("Kein Zugriff auf das Netzwerk möglich"); phantom.exit(); ) else ( waitFor(function() ( return page.evaluate(function()( var el = document.getElementById("qunit-testresult"); if (el && el.innerText.match("completed")) ( return true; ) return false; )); ), function()( var failedNum = page.evaluate(function()( var el = document.getElementById("qunit-testresult"); console.log(el.innerText); try ( return document.getElementsByClassName("fail" ).innerHTML.length; ) catch (e) (return 0; ) return 10000; )); phantom.exit((parseInt(failedNum, 10) > 0) ? 1: 0); )); ) ));

Um Ergebnismeldungen in der Konsole anzuzeigen, müssen Sie die Protokollierungsfunktion zum Testskript hinzufügen.

Jetzt ist die Website verfügbar, um Kenntnisse zu folgenden Themen zu testen: HTML, css, JavaScript, PHP, SQL.

Jeder Test besteht aus 10 Fragen zu einem bestimmten Thema. Bei jeder Frage habe ich versucht, die unterschiedlichsten Anwendungsbereiche einer bestimmten Sprache anzusprechen, um Ihren Kenntnisstand möglichst genau zu überprüfen.

Natürlich alles Tests sind kostenlos und jeder kann durchgehen.

Testprozedur:

  1. Folge dem Link " Starten Sie den Test“ des entsprechenden Tests.
  2. Beantworten Sie die Fragen, indem Sie auswählen der Einzige Korrekte Möglichkeit.
  3. Nach Abschluss des Tests werden Sie sehen Ihr Ergebnis, Anzahl Fehler, und auch Analyse jeder Frage aus der Prüfung.

Aufmerksamkeit! Es wird nicht funktionieren, zur vorherigen Frage zurückzukehren, also denken Sie nach, bevor Sie antworten.

Tests derzeit verfügbar

  1. HTML

    • Gesamttest bestanden: 75424 Menschen
    • Durchschnittsnote: 2,83 von 5 Punkte.

    Grundwissenstest HTML. Sie müssen grundlegende Kenntnisse haben HTML-Tags und ihre bestimmungsgemäße Verwendung. Es ist auch notwendig, die Merkmale des Standards zu verstehen XHTML 1.1.

  2. css

    • Gesamttest bestanden: 32828 Menschen
    • Durchschnittsnote: 3,37 von 5 Punkte.

    Der Test testet die Grundkenntnisse css. Um den Test erfolgreich zu bestehen, müssen Sie die grundlegenden Typen von Selektoren (ihre Syntax), die grundlegenden Eigenschaften und ihre möglichen Werte kennen und auch den Zweck der beliebtesten Pseudoelemente kennen.

  3. JavaScript

    • Gesamttest bestanden: 24845 Menschen
    • Durchschnittsnote: 3,31 von 5 Punkte.

    Dieses Quiz testet Ihre Kenntnisse der JavaScript-Sprache. Fragen aus dem Test decken unterschiedliche Anwendungsbereiche ab gegebene Sprache. Es gibt viele Fragen zum Verständnis "kleiner" Nuancen. Ansonsten müssen Sie grundlegende Dinge wissen: Arbeiten mit Variablen, grundlegende JavaScript-Funktionen, Operatorprioritäten und so weiter.

  4. PHP

    • Gesamttest bestanden: 33239 Menschen
    • Durchschnittsnote: 3.03 von 5 Punkte.

    Dieses Quiz testet Ihre Kenntnisse der PHP-Sprache. Sie müssen grundlegende PHP-Konstrukte kennen, mit Variablen, Sitzungen, Umleitungsimplementierung und anderen Standarddingen arbeiten.
    Überzeugende Anfrage: Der Test enthält viele Fragen wie: "Was wird das Skript ausgeben?". Eine große Bitte, kopieren Sie es nicht und überprüfen Sie es. Sei ehrlich zu dir selbst.

  5. SQL

    • Gesamttest bestanden: 18014 Menschen
    • Durchschnittsnote: 3,28 von 5 Punkte.

    Dieser Test testet Ihre Sprachkenntnisse SQL-Abfragen. Die Fragen decken nur die grundlegendsten Kenntnisse dieser Sprache ab, ohne Vertiefung. Sie benötigen Kenntnisse der grundlegendsten SQL-Abfragen sowie deren kompetente Anwendung.

Am Beispiel einer einfachen Rechneranwendung auf Node.js. Wir werden mit dem Mocha-Framework testen.

Was unsere Anwendung können soll:

  • Addiere, subtrahiere, dividiere und multipliziere zwei beliebige Zahlen;
  • Eine Warnung anzeigen und beenden, wenn etwas anderes als eine Zahl eingegeben wurde;
  • Es muss auch eine Befehlszeilenschnittstelle vorhanden sein, damit der Endbenutzer die Anwendung verwenden kann.

Was wir brauchen:

  • Node.js und npm
  • Kenntnisse in JavaScript: Syntax und Codestruktur, Datentypen, mathematische Operationen und bedingte Ausdrücke.

Nachdem Sie die Ziele festgelegt haben, können Sie damit beginnen, die Umgebung für Tests und Entwicklung einzurichten.

Umgebung einrichten

Da wir Node.js verwenden, müssen wir eine lokale Umgebung für Dateien und Abhängigkeiten erstellen.

Erstellen neuer Ordner kalk. Wechseln Sie in der Befehlszeile in dieses Verzeichnis und erstellen Sie ein neues Projekt mit npm init , das erstellt neue Datei Paket.json für unser Programm.

Sie werden aufgefordert, den Paketnamen, die Version, die Beschreibung und andere Informationen über das Paket einzugeben. Sie können einen Namen eingeben calc.js und weiter drücken Eingeben Standardwerte zuzuweisen. Wenn Sie zum Testbefehl gelangen, geben Sie mocha ein - dies ist das Testframework, das wir verwenden werden:

Testbefehl: Mokka

Nach Eingabe aller Informationen erstellt das Skript eine Datei Paket.json, die in etwa so aussieht:

( "name": "calc.js", "version": "1.0.0", "description": "Einfacher Taschenrechner in Node.js", "main": "index.js", "scripts": ( " test": "mokka" ), "autor": "", "lizenz": "ISC" )

Der letzte Schritt in diesem Schritt ist die Installation von Mocha. Geben Sie zur Installation den folgenden Befehl ein:

npm install --save-dev mocha

Nachdem Sie diesen Befehl angewendet haben, wird ein Ordner angezeigt node_modules, Datei Paketsperre.json, und in der Datei Paket.json Es erscheinen folgende Zeilen:

"devDependencies": ( "mocha": "^4.0.1" )

Erstellen Sie eine Datei test.js. Wir werden das eingebaute Modul in Node.js verwenden behaupten um zu überprüfen, ob wahr und wahr wahr sind. Da es wahr ist, sollte der Test bestehen:

Konstante behaupten = erfordern ("bestätigen"); it("sollte wahr zurückgeben", () => (asser.equal(true, true); ));

Führen Sie nun den Test über die Befehlszeile aus:

$ npm test > mocha ✓ sollte true 1 passing zurückgeben (8ms)

Der Test verlief wie erwartet, die Einrichtung der Umgebung ist also abgeschlossen. Entfernen von test.js alles außer der Zeile const assert = require("assert"); .

Wir werden die Datei verwenden test.js während des gesamten Anwendungsentwicklungsprozesses. Erstellen Sie zwei weitere Dateien: operationen.js für Arithmetik- und Validierungsfunktionen und calc.js für die Bewerbung selbst. Wir verwenden so viele Dateien, dass sie nicht zu lang und kompliziert werden. Hier ist unsere aktuelle Dateiliste:

  • calc.js;
  • node_modules;
  • operationen.js;
  • Paketsperre.json;
  • Paket.json;
  • test.js;

Fügen wir die erste hinzu echte Prüfung für unsere Bewerbung.

Mathematische Operationen hinzufügen

Zunächst einmal muss unsere Anwendung zwei beliebige Zahlen addieren, subtrahieren, dividieren und multiplizieren können. Für jede dieser Operationen müssen wir also eine separate Funktion erstellen.

Beginnen wir mit der Addition. Wir werden einen Test schreiben, der eindeutig die erwartete Summe zweier Zahlen ergibt. Im folgenden Code prüfen wir mit der Funktion add() 4, ob die Summe von 1 und 3 gleich ist:

Konstante behaupten = erfordern ("bestätigen"); it("findet die Summe von 1 und 3 korrekt", () => (asser.equal(add(1, 3), 4); ));

Nachdem wir den Test mit dem Befehl npm test ausgeführt haben, sehen wir Folgendes:

> mocha 0 bestanden (9ms) 1 fehlgeschlagen 1) findet die Summe von 1 und 3 korrekt: ReferenceError: add is not defined at Context.it (test.js:5:16) npm ERR! im Test durchgefallen. Siehe oben für weitere Details.

Der Test ist mit einem ReferenceError: add is not defined fehlgeschlagen. Wir testen die Funktion add(), die es noch nicht gibt, daher ist dieses Ergebnis durchaus zu erwarten.

Lassen Sie uns eine add()-Funktion in einer Datei erstellen operationen.js:

Const add = (x, y) => (+x) + (+y);

Diese Funktion nimmt zwei Argumente x und y und gibt ihre Summe zurück. Sie haben vielleicht bemerkt, dass wir (+x) + (+y) anstelle von x + y schreiben. Wir verwenden den unären Operator, um das Argument in eine Zahl umzuwandeln, falls die Eingabe ein String ist.

Hinweis Dies verwendet eine von ES6 hinzugefügte Pfeilfunktion und eine implizite Rückgabe.

Da wir Node.js verwenden und den Code in mehrere Dateien aufteilen, müssen wir module.exports verwenden, um den Code zu exportieren:

Const add = (x, y) => (+x) + (+y); module.exports = (hinzufügen)

Am Anfang der Datei test.js Wir importieren Code aus operationen.js mit require() . Da wir die Funktion über die Operationsvariable verwenden, müssen wir add() in operations.add() ändern:

Konstante Operationen = require(./operations.js"); const assert = require("assert"); it("findet die Summe von 1 und 3 korrekt", () => (asser.equal(operations.add(1, 3), 4); ));

Führen wir den Test durch:

$ npm test > mocha ✓ findet die Summe aus 1 und 3 korrekt 1 passing (8ms)

Wir haben jetzt eine funktionierende Funktion und die Tests werden erfolgreich bestanden. Da die Funktionen der anderen Operationen ähnlich funktionieren, ist das Hinzufügen von Tests für subtract() , multiply() und divide() einfach:

It("findet die Summe von 1 und 3 korrekt", () => (asser.equal(operations.add(1, 3), 4); )); it("findet die Summe von -1 und -1 korrekt", () => (asser.equal(operations.add(-1, -1), -2); )); it("findet den Unterschied zwischen 33 und 3 korrekt", () => (asser.equal(operations.subtract(33, 3), 30); )); it("findet das Produkt von 12 und 12 korrekt", () => (asser.equal(operations.multiply(12, 12), 144); )); it("findet den Quotienten von 10 und 2 korrekt", () => (asser.equal(operations.divide(10, 2), 5); ));

Lassen Sie uns nun alle Funktionen erstellen und exportieren test.js:

Const add = (x, y) => (+x) + (+y); const subtract = (x, y) => (+x) - (+y); const multiplizieren = (x, y) => (+x) * (+y); const dividieren = (x, y) => (+x) / (+y); module.exports = ( addieren, subtrahieren, multiplizieren, dividieren, )

Und neue Tests durchführen:

$ npm test > mocha ✓ findet korrekt die Summe von 1 und 3 ✓ findet korrekt die Summe von -1 und -1 ✓ findet korrekt die Differenz zwischen 33 und 3 ✓ findet korrekt das Produkt von 12 und 12 ✓ findet korrekt den Quotienten von 10 und 2 5 Passing (8ms)

Alle Tests wurden erfolgreich bestanden, sodass wir jetzt sicher sein können, dass die Hauptfunktionen unserer Anwendung korrekt funktionieren. Jetzt können wir einige zusätzliche Validierungen durchführen.

Validierung hinzufügen

Im Moment, wenn der Benutzer eine Zahl eingibt und die gewünschte Operation auswählt, funktioniert alles einwandfrei. Was passiert jedoch, wenn Sie versuchen, die Summe einer Zahl und einer Zeichenfolge zu finden? Die Anwendung versucht, die Operation auszuführen, aber da sie eine Zahl erwartet, gibt sie NaN zurück.

Anstatt einige seltsame Werte zurückzugeben, ist es an der Zeit, die zweite Aufgabe zu erledigen – die Anwendung dazu zu bringen, eine Warnung anzuzeigen und sich zu beenden, wenn das Eingabeargument keine Zahl ist.

Zuerst müssen Sie eine Funktion schreiben, die überprüft, ob die Eingabe eine Zahl ist oder nicht. Die Anwendung sollte nur mit Zahlen funktionieren, daher behandeln wir drei Situationen:

  1. Beide Eingaben sind Zahlen.
  2. Eine Eingabe ist eine Zahl und die andere eine Zeichenfolge.
  3. Beide Eingänge sind Strings.
it("meldet einen Fehler, wenn eine Zeichenfolge anstelle einer Zahl verwendet wird", () => (asser.equal(operations.validateNumbers("sammy", 5), false); )); it("meldet einen Fehler, wenn zwei Strings anstelle von Zahlen verwendet werden", () => (asser.equal(operations.validateNumbers("sammy", "sammy"), false); )); it("Erfolg bei Verwendung von zwei Zahlen", () => (asser.equal(operations.validateNumbers(5, 5), true); ));

Die Funktion validateNumbers() validiert beide Parameter. Die Funktion isNaN() prüft, ob der Parameter keine Zahl ist, und gibt andernfalls false zurück. Andernfalls wird true zurückgegeben, was eine erfolgreiche Validierung bedeutet.

Const validateNumbers = (x, y) => ( if (isNaN(x) && isNaN(y)) (return false; ) return true; )

Vergessen Sie nicht, validateNumbers zu module.exports am Ende der Datei hinzuzufügen. Jetzt können Sie neue Tests durchführen:

$ npm test 1) meldet einen Fehler bei der Verwendung eines Strings anstelle einer Zahl ✓ meldet einen Fehler bei der Verwendung von zwei Strings anstelle von Zahlen ✓ Erfolg bei der Verwendung von zwei Zahlen 7 bestanden (12 ms) 1 fehlgeschlagen 1) meldet einen Fehler bei der Verwendung eines Strings stattdessen einer Zahl: AssertionError : wahr == falsch + erwartet - tatsächlich -wahr + falsch

Zwei Tests wurden bestanden, aber einer ist fehlgeschlagen. Der Test für zwei Zahlen war erfolgreich, ebenso der Test für zwei Saiten. Was kann nicht über die Überprüfung auf die Eingabe einer Zeichenfolge und einer Zahl gesagt werden.

Wenn wir unsere Funktion noch einmal betrachten, können wir das sehen beide Parameter müssen NaN sein, damit die Funktion false zurückgibt. Wenn wir den gleichen Effekt erzielen wollen, wenn mindestens einer der Parameter NaN ist, müssen wir && durch || ersetzen :

Const validateNumbers = (x, y) => ( if (isNaN(x) || isNaN(y)) (return false; ) return true; )

Wenn Sie npm test nach diesen Änderungen erneut ausführen, werden alle Tests bestanden:

✓ meldet einen Fehler, wenn ein String anstelle einer Zahl verwendet wird ✓ meldet einen Fehler, wenn zwei Strings anstelle von Zahlen verwendet werden ✓ Erfolg, wenn zwei Zahlen verwendet werden 8 passing (9ms)

Wir haben alle Funktionen unserer Anwendung getestet. Funktionen führen erfolgreich mathematische Operationen durch und validieren Eingaben. Die letzte Phase ist die Erstellung der Benutzeroberfläche.

Erstellen einer Schnittstelle

Wir haben bereits die notwendigen Funktionen, aber der Benutzer kann sie noch in keiner Weise verwenden. Wir brauchen also eine Schnittstelle. Für unsere Anwendung erstellen wir eine Befehlszeilenschnittstelle.

Im Moment die Datei calc.js sollte leer sein. Hier wird unsere Bewerbung gespeichert. Zuerst müssen Sie Funktionen aus importieren operationen.js:

Konstante Operationen = require(./operations.js");

Die Schnittstelle selbst verwendet das integrierte Readline-CLI-Modul von Node.js:

Const readline = require("readline");

Nachdem Sie alles, was Sie benötigen, importiert haben, können Sie mit der Erstellung der Anwendung beginnen. Um die Schnittstelle zu erstellen, verwenden wir readline , die über die Variable rl verfügbar ist:

Const rl = readline.createInterface (( Eingabe: process.stdin, Ausgabe: process.stdout ));

Das erste, was der Benutzer nach dem Start des Programms sehen sollte, ist eine Willkommensnachricht und eine Gebrauchsanweisung. Dazu verwenden wir console.log() :

Console.log(` Calc.js Sie haben einen Node.js-Rechner geöffnet! Version: 1.0.0. Verwendung: Der Benutzer muss zwei Zahlen eingeben und dann auswählen, was damit geschehen soll. `);

Bevor wir uns mit den Taschenrechnerfunktionen selbst befassen, wollen wir überprüfen, ob console.log() so funktioniert, wie es sollte. Wir lassen das Programm eine Nachricht ausgeben und beenden. Fügen Sie dazu am Ende einen Aufruf der Methode rl.close() hinzu.

Um die Anwendung auszuführen, geben Sie node gefolgt von einem Dateinamen ein:

$ node calc.js Calc.js Sie haben den Node.js-Rechner geöffnet! Version: 1.0.0. Verwendung: Der Benutzer muss zwei Nummern eingeben und dann auswählen, was damit geschehen soll.

Das Programm zeigt eine Willkommensnachricht an und wird beendet. Jetzt müssen wir Benutzereingaben hinzufügen. Der Benutzer muss zwei Zahlen und eine Operation auswählen. Jede Eingabe wird von der Methode rl.question() angefordert:

Rl.question("Geben Sie die erste Zahl ein: ", (x) => ( rl.question("Geben Sie die zweite Zahl ein: ", (y) => ( rl.question(` Wählen Sie eine der folgenden Operationen: Addieren ( +) Subtrahieren (-) Multiplikation (*) Division (/) Ihre Auswahl: `, (choice) => ( // hier erscheint mehr Code rl.close(); )); )); ));

Der Variablen x wird die erste Zahl zugewiesen, y der zweiten, und choice ist die ausgewählte Operation. Jetzt fordert unser Programm Eingaben auf, macht aber nichts mit den empfangenen Daten.

Nach der dritten Eingabe müssen Sie überprüfen, ob nur Zahlen eingegeben wurden. Dazu verwenden wir die Funktion validateNumbers(). Mit dem NOT-Operator prüfen wir, ob Zahlen eingegeben wurden, und wenn nicht, beenden wir das Programm:

If (!operations.validateNumbers(x, y)) ( console.log("Nur Zahlen sind erlaubt! Bitte starten Sie das Programm neu."); )

Wenn alles korrekt eingegeben wurde, müssen Sie jetzt die entsprechende zuvor erstellte Operationsmethode ausführen. Um die vier Auswahlmöglichkeiten zu verarbeiten, verwenden wir eine switch-Anweisung und geben das Ergebnis der Operation aus. Wenn eine nicht vorhandene Operation ausgewählt wurde, wird der Standardblock ausgeführt und der Benutzer aufgefordert, es erneut zu versuchen:

If (!operations.validateNumbers(x, y)) ( console.log("Nur Zahlen können eingegeben werden! Bitte starten Sie das Programm neu."); ) else ( switch (choice) ( case "1": console.log(` Summe $(x) und $(y) ist gleich $(operations.add(x, y)).`); break; case "2": console.log(`Difference of $(x) and $(y) equals $( operations.subtract(x, y)).`); break; case "3": console.log(`Das Produkt von $(x) und $(y) ist gleich $(operations.multiply(x, y) ).`) ; break; case "4": console.log(`Private $(x) and $(y) equals $(operations.divide(x, y)).`); break; default: console.log ("Bitte starte das Programm neu und wähle eine Zahl zwischen 1 und 4."); Pause; ) )

Hinweis Die Funktionen von console.log() verwenden hier Vorlagenzeichenfolgen, die Ausdrücke zulassen.

/** * Ein einfacher Node.js-Rechner, der die Rechner-App verwendet, die * die integrierte Readline-Befehlszeilenschnittstelle verwendet. */ const operations = require(./operations.js"); const readline = require("readline"); // readline verwenden, um eine Schnittstelle zu erstellen const rl = readline.createInterface(( input: process.stdin, output: process.stdout )); console.log(` Calc.js Sie haben einen Node.js-Rechner geöffnet! Version: 1.0.0. Verwendung: Der Benutzer muss zwei Zahlen eingeben und dann auswählen, was damit geschehen soll. `); rl.question("Geben Sie die erste Zahl ein: ", (x) => ( rl.question("Geben Sie die zweite Zahl ein: ", (y) => ( rl.question(` Wählen Sie eine der folgenden Operationen: Addiere ( +) Subtrahieren (-) Multiplikation (*) Division (/) Ihre Wahl: `, (choice) => ( if (!operations.validateNumbers(x, y)) ( console.log("Sie können nur Zahlen eingeben! Bitte starte das Programm neu."); ) else ( switch (choice) ( case "1": console.log(`Die Summe von $(x) und $(y) ist gleich $(operations.add(x, y)). `); break; case "2": console.log(`Der Unterschied zwischen $(x) und $(y) ist $(operations.subtract(x, y)).`); break; case "3": console.log(`Das Produkt von $( x) und $(y) ist gleich $(operations.multiply(x, y)).`); break; case "4": console.log(`Private $(x) and $(y) equals $(operations. divide(x, y)).`); break; default: console.log("Bitte starte das Programm neu und wähle eine Zahl zwischen 1 und 4."); break; ) ) rl.close(); )); )) ; ));

Jetzt ist unsere Anwendung fertig. Lassen Sie uns am Ende seine Arbeit überprüfen. Geben Sie 999 und 1 ein und wählen Sie die Subtraktionsoperation aus:

$ node calc.js Geben Sie die erste Zahl ein: 999 Geben Sie die zweite Zahl ein: 1 Ihre Wahl: 2 Die Differenz zwischen 999 und 1 ist 998.

Das Programm hat seine Arbeit erfolgreich abgeschlossen und das richtige Ergebnis angezeigt. Herzlichen Glückwunsch, Sie haben mit Node.js einen einfachen Taschenrechner geschrieben und die Grundlagen der TDD-Entwicklung gelernt.



Wird geladen...
Spitze