Wo die Tests ausgeführt werden

Automatisierte Tests können in der Regel durch manuelles Ausführen eines Skripts oder mithilfe eines Hilfsprogramms aus einem Test-Framework, oft als Test-Runner bezeichnet, zum Suchen und Ausführen von Tests ausgeführt werden. Möglicherweise müssen Sie Ihre Skripts jedoch nicht immer manuell ausführen. Es gibt eine Reihe von Möglichkeiten zum Ausführen von Tests, die zu verschiedenen Zeitpunkten des Entwicklungszyklus Feedback und Zuverlässigkeit liefern können.

Erforderliches Skript

Webprojekte verfügen normalerweise über eine Konfigurationsdatei (die Datei package.json), die von npm, pnpm, Bun oder ähnlich eingerichtet wird. Diese Konfigurationsdatei enthält die Abhängigkeiten Ihres Projekts, weitere Informationen sowie Hilfsskripts. Diese Hilfsskripts können Informationen zum Erstellen, Ausführen oder Testen Ihres Projekts beinhalten.

Innerhalb von package.json müssen Sie ein Skript mit dem Namen test hinzufügen, das beschreibt, wie die Tests ausgeführt werden. Das ist wichtig, weil bei der Verwendung von npm oder einem ähnlichen Tool dem "Test"-Skript eine besondere Bedeutung hat. Dieses Skript kann einfach auf eine einzelne Datei verweisen, die eine Ausnahme wie etwa node tests.js auslöst. Wir empfehlen jedoch, sie zu verwenden, um auf einen vorhandenen Test-Runner zu verweisen.

Wenn Sie Vitest als Test-Runner verwenden, sieht Ihre package.json-Datei so aus:

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

Wenn Sie npm test mit dieser Datei ausführen, wird der Standardsatz von Vitest einmal ausgeführt. In Vitest werden standardmäßig alle Dateien mit der Endung „.test.js“ oder ähnlich gesucht und ausgeführt. Abhängig vom ausgewählten Test-Runner kann der Befehl geringfügig anders sein.

Wir haben uns für Vitest entschieden, ein immer beliebteres Test-Framework als Beispiele im Verlauf dieses Kurses. Weitere Informationen zu dieser Entscheidung finden Sie in Vitest als Test-Runner. Sie sollten jedoch daran denken, dass Test-Frameworks und Runner – auch für verschiedene Sprachen – tendenziell einen gemeinsamen Dialekt haben.

Manueller Testaufruf

Das manuelle Auslösen Ihrer automatisierten Tests (z. B. mit npm test im vorherigen Beispiel) kann praktisch sein, wenn Sie aktiv an einer Codebasis arbeiten. Wenn Sie während der Entwicklung einer Funktion Tests schreiben, erhalten Sie ein Gefühl dafür, wie das Feature funktionieren sollte. Dies berührt das Konzept der testgesteuerten Entwicklung (Test-Driven Development, TDD).

Test-Runner haben in der Regel einen kurzen Befehl, den Sie zum Ausführen einiger oder aller Ihrer Tests aufrufen können, und möglicherweise einen Watcher-Modus, der die Tests beim Speichern noch einmal ausführt. Das alles sind hilfreiche Optionen bei der Entwicklung einer neuen Funktion. Sie wurden entwickelt, um das Schreiben einer neuen Funktion und ihrer Tests oder beides zu vereinfachen. Und das alles mit schnellem Feedback. Vitest arbeitet beispielsweise standardmäßig im Watcher-Modus: Der Befehl vitest sucht nach Änderungen und führt alle gefundenen Tests noch einmal aus. Wir empfehlen, dieses Fenster beim Schreiben von Tests in einem anderen Fenster geöffnet zu lassen, damit Sie bei der Entwicklung schnelles Feedback zu Ihren Tests erhalten können.

Bei einigen Läufern kannst du Tests auch in deinem Code als only markieren. Wenn Ihr Code only-Tests enthält, werden beim Durchführen von Tests nur diese Tests ausgelöst, sodass Fehler in der Testentwicklung schneller und einfacher behoben werden können. Auch wenn alle Tests schnell abgeschlossen werden, kann die Verwendung von only Ihren Aufwand reduzieren und die Ablenkung durch das Ausführen von Tests vermeiden, die nichts mit der Funktion oder dem Test zu tun haben, an dem Sie arbeiten.

Bei kleinen Projekten, insbesondere Projekten mit nur einem Entwickler, sollten Sie es sich außerdem zur Gewohnheit machen, regelmäßig die gesamte Testsuite Ihrer Codebasis auszuführen. Dies ist besonders hilfreich, wenn Ihre Tests klein und schnell abgeschlossen sind (alle Tests in höchstens wenigen Sekunden). So können Sie prüfen, ob alles funktioniert, bevor Sie fortfahren.

Tests im Rahmen der Vorab-Einreichung oder Überprüfung durchführen

In vielen Projekten wird geprüft, ob eine Codebasis ordnungsgemäß funktioniert, wenn Code wieder mit dem main-Zweig zusammengeführt werden soll. Wenn Sie neu im Testen sind, aber in der Vergangenheit an Open-Source-Projekten mitgewirkt haben, ist Ihnen wahrscheinlich aufgefallen, dass ein Teil des Pull-Anfrageprozesses (PR) bestätigt, dass alle Tests des Projekts bestanden wurden, was bedeutet, dass Ihr neuer Beitrag sich nicht negativ auf das bestehende Projekt ausgewirkt hat.

Wenn Sie die Tests lokal ausführen, weiß das Online-Repository Ihres Projekts (z. B. GitHub oder ein anderer Codehosting-Dienst) nicht, dass Ihre Tests bestanden wurden. Wenn Sie die Tests als Aufgabe für das Vorabsenden ausführen, sehen alle Beitragenden, dass alles funktioniert.

GitHub bezeichnet diese zum Beispiel als "Statusprüfungen", die Sie über GitHub-Aktionen hinzufügen können. GitHub-Aktionen sind im Grunde eine Art Test: Jeder Schritt muss erfolgreich sein (d. h. es darf nicht fehlschlagen oder ein Error auslösen), damit die Aktion erfolgreich ist. Sie können Aktionen auf alle PRs für ein Projekt anwenden. Bei einem Projekt kann es erforderlich sein, dass Aktionen bestanden wurden, bevor Sie Code beitragen können. Die Node.js-Standardaktion von GitHub führt npm test als einen der Schritte aus.

Screenshot eines GitHub Actions-Testprozesses.
Screenshot eines GitHub Actions-Testprozesses.

Bei diesem Testansatz wird versucht, dafür zu sorgen, dass die Codebasis immer „grün“ ist. Dazu wird kein Code akzeptiert, der seine Tests nicht erfolgreich ausführt.

Tests im Rahmen der Continuous Integration ausführen

Nachdem Ihre grüne PR akzeptiert wurde, führen die meisten Codebasis Tests noch einmal basierend auf dem main-Zweig Ihres Projekts und nicht auf der vorherigen PR-Methode aus. Dies kann sofort oder regelmäßig erfolgen (z. B. stündlich oder nachts). Diese Ergebnisse werden häufig als Teil eines Dashboards für Continuous Integration (CI) angezeigt, das den Gesamtzustand des Projekts anzeigt.

Dieser CI-Schritt kann redundant erscheinen, insbesondere bei Projekten mit einer kleinen Codebasis, d. h. bei Tests, die bei der Überprüfung bestanden wurden. Sie sollten also bestanden werden, sobald eine Änderung erfolgt ist. Dies ist jedoch nicht immer der Fall. Ihre Tests können plötzlich fehlschlagen, selbst wenn erfolgreiche grüne Ergebnisse erzielt wurden. Dies kann unter anderem folgende Gründe haben:

  • Mehrere Änderungen wurden "gleichzeitig" akzeptiert, was manchmal als Race-Bedingung bezeichnet wird, und beeinflussen sich auf subtile, nicht getestete Weise gegenseitig.
  • Ihre Tests sind nicht reproduzierbar oder sie testen "unzuverlässigen" Code. Beide Tests können ohne Codeänderungen bestanden werden oder scheitern.
    • Dies kann vorkommen, wenn Sie von Systemen außerhalb Ihrer Codebasis abhängig sind. Stellen Sie sich für einen Proxy vor, Sie testen bei Math.random() > 0.05 – das würde in 5 % der Fälle zufällig fehlschlagen.
  • Einige Tests sind zu kostspielig oder teuer, um sie bei jeder PR durchzuführen, z. B. End-to-End-Tests (mehr dazu unter Arten von automatisierten Tests). Außerdem können sie im Laufe der Zeit ohne Benachrichtigungen unterbrochen werden.

Keines dieser Probleme lässt sich lösen, aber es lohnt sich zu bedenken, dass Tests und Softwareentwicklung im Allgemeinen niemals eine exakte Wissenschaft sein werden.

Ein Zwischenfall beim Rollback

Wenn Tests im Rahmen der Continuous Integration ausgeführt werden und selbst wenn Tests im Rahmen einer Statusprüfung ausgeführt werden, ist es möglich, dass der Build in einem „roten“ Zustand oder einem anderen Status landet, der ein Fehlschlagen der Tests bedeutet. Wie bereits erwähnt, kann dies aus verschiedenen Gründen auftreten, z. B. mit Race-Bedingungen bei der Testeinreichung oder unzuverlässigen Tests.

Bei kleineren Projekten könnte Ihr Instinkt sein, sie als Krise zu betrachten! Beenden Sie alles, machen Sie ein Rollback oder machen Sie die betreffende Änderung rückgängig und kehren Sie in einen bekanntermaßen fehlerfreien Zustand zurück. Dies kann ein gültiger Ansatz sein. Sie sollten jedoch bedenken, dass Tests (und Software im Allgemeinen!) eine Mittelstellung zum Ziel und keine Zielsetzung an sich sind. Ihr Ziel ist wahrscheinlich, Software zu schreiben, nicht dafür, dass alle Tests bestanden werden. Stattdessen können Sie einen Roll-Forward-Vorgang durchführen, indem Sie die funktionsgefährdende Änderung mit einer anderen Änderung zur Behebung der fehlgeschlagenen Tests nachbearbeiten.

Andererseits haben Sie vielleicht große Projekte gesehen oder daran gearbeitet, die ununterbrochen defekt sind. Oder schlimmer noch, das große Projekt hat einen instabilen Test, der häufig genug abgebrochen wird, um eine Ermüdung bei Entwicklern zu verursachen. Dies ist oft ein existierendes Problem, das von Führungskräften gelöst werden muss: Diese Tests können sogar abgeschafft werden, weil sie als „die Entwicklung behindern“ empfunden werden.

Es gibt keine schnelle Lösung für dieses Problem, aber es kann helfen, sicherer zu schreiben (Weiterbildungen) und den Umfang der Tests zu reduzieren (Vereinfachung), damit Fehler leichter identifiziert werden können. Eine größere Anzahl von Komponententests oder Integrationstests (weitere Typen unter Arten automatisierter Tests) kann mehr Sicherheit bieten als ein großer End-to-End-Test, der schwierig zu verwalten ist und versucht, alles gleichzeitig zu erledigen.

Ressourcen

Wissen testen

Wie heißt das spezielle Skript, auf das npm und ähnliche Programme beim Testen achten?

check
Test
vorab senden
verify