Arten automatischer Tests

Die Namen, die verschiedenen Testtypen gegeben werden, haben in der Regel gemeinsame Themen in verschiedenen Codebasen. Sie haben jedoch keine besonders strengen Definitionen. Dieser Kurs enthält einige Richtlinien zur Bedeutung der einzelnen Testtypen. Andere Ressourcen können jedoch andere Definitionen geben.

Auf den vorherigen Seiten gab es Beispiele für Einheitentests und für Komponententests, die sich in unserem Beispiel auf eine React-Komponente beziehen. Beides können wir in die Testpyramide (oder eine andere Form) setzen, da sie wenig komplex sind und schnell ausgeführt werden können, aber möglicherweise nicht so nützlich sind wie ein komplexerer Integrationstest.

Beispiele für Teststrategieformen: eine Pyramide, eine geschliffene Raute, eine Eistüte, ein Sechseck und eine Trophäe.
Teststrategien können vielfältig sein.

Gängige Testtypen

Unittests

Unittests haben den kleinsten Umfang. Sie werden tendenziell verwendet, um kleine Teile von Code oder rein zustandslosen Code fast auf mathematische Weise zu testen: Wenn ich Ihrem Code die Eingaben X, Y und Z zur Verfügung stelle, sollte die Ausgabe A, B und C sein.

Code mit Einheitentests hat normalerweise keine externen Abhängigkeiten, z. B. vom Abrufen aus einem Netzwerk oder implizit unter Verwendung anderer Funktionen oder Bibliotheken. Er ist ein Baumknoten Ihres Codes, den Sie selbst „ausschneiden“ und testen können.

Einheitentests werden normalerweise schnell geschrieben und ausgeführt. Es ist jedoch immer möglich, dass das Testen kleiner Codeeinheiten keine nützlichen Informationen liefert. Häufig bedeutet die fehlende Interaktion einer Codeeinheit mit anderem Code, dass Sie besser auf einer höheren Ebene testen sollten, um das Risiko zu reduzieren.

Komponententests

Für Webentwickler ist der Name „Component“ überladen. Das bedeutet oft eine für Nutzer sichtbare Komponente wie eine React- oder Web-Komponente. Ihre allgemeinere Definition ist ein testbarer Arbeitsblock, z. B. eine Klasse mit externen Abhängigkeiten. Um effektiv getestet zu werden, müssen die Abhängigkeiten dieser Komponente ausgebildet oder übersprungen werden.

Da moderne Webentwicklungsmethoden auf dem Konzept einer Komponente basieren, sind Komponententests eine praktische Denkweise für Tests: Sie können beispielsweise entscheiden, dass für jede Komponente ein Test erforderlich ist. Komponententests sind auch einfach nachzuverfolgen, wenn ein einzelner Entwickler oder ein kleines Team klare Eigentumsrechte für eine Komponente geltend macht. Es kann jedoch schwierig sein, komplexe Abhängigkeiten zu simulieren.

Integrationstests

Dabei wird in der Regel eine kleine Gruppe von Komponenten, Modulen, Subsystemen oder anderen relevanten Teilen Ihres Codes getestet, um sicherzustellen, dass sie richtig funktionieren. Dies ist eine sehr vage Definition. Als Webentwickler können Sie sich vorstellen, dass der zu testende Code nicht die tatsächliche Produktionsversion Ihrer Website (oder sogar eine ähnliche Version) Ihrer Website ist, sondern dass er dennoch verschiedene verwandte Komponenten Ihres Systems miteinander verbindet.

Dies kann sogar „echte“ Abhängigkeiten umfassen, z. B. eine externe Datenbank im Testmodus und nicht eine reine Simulation. Anstatt beispielsweise anzugeben, dass query() immer dieselben zwei Einträge zurückgibt, kann mit dem Integrationstest bestätigt werden, dass eine Testdatenbank etwas enthält. Die Daten selbst sind weniger wichtig, aber Sie testen jetzt, ob eine Datenbank verbunden und erfolgreich abgefragt werden kann.

Es ist möglich, relativ einfache Integrationstests mit weitreichenden Auswirkungen zu schreiben, die mithilfe von Assertions überprüft werden können, da eine einzelne Aktion, die mit verschiedenen Komponenten verbunden ist, eine Reihe von messbaren Auswirkungen haben kann. Aus diesem Grund können Integrationstests effektiv zeigen, dass Ihr komplexes System wie vorgesehen ausgeführt wird. Sie können jedoch schwer zu schreiben und zu pflegen sein und zu unnötiger Komplexität führen. Wenn du beispielsweise ein FakeUserService für einen Integrationstest schreibst, wird die Anforderung hinzugefügt, dass sowohl dieses als auch das RealUserService eine UserService implementieren müssen.

Smoke Tests

Dies sind Tests, die sehr schnell abgeschlossen werden sollten und ermitteln sollten, ob Ihre Codebasis in einem vernünftigen Zustand ist. In der Praxis bedeutet dies im Wesentlichen, dass einfache Tests für Code durchgeführt werden, was weitreichende Auswirkungen auf die Nutzererfahrung hat.

Bei einer großen angemeldeten Webanwendung könnte dies beispielsweise dafür sorgen, dass das Anmelde- und Authentifizierungssystem funktioniert, da die Anwendung ohne sie unbrauchbar ist und weitere Tests irrelevant sind.

Smoke-Tests eignen sich gut für die Ausführung unter dem test-Skript Ihrer package.json-Datei in einer großen Codebasis. Manuelle Tests können auch als eine Art Rauchtest dienen.

Regressionstests

Regressionstests sind eine Art von Rauchtests, mit der sichergestellt wird, dass vorhandene Funktionen weiterhin funktionieren oder dass alte Fehler nach einer neuen Version oder einer anderen Funktionsentwicklung nicht wieder eingeführt werden.

Dies entspricht dem Konzept der testbasierten Entwicklung. Testläufe, die geschrieben wurden, um einen Fehler explizit auszulösen, und später zur Behebung des Fehlers verwendet werden, zählen als Regressionstestfälle, da ihr Vorhandensein verhindern sollte, dass der gleiche Fehler erneut auftritt.

Regressionstests können jedoch auch ohne gute Lösung zum Problem werden. Dieser Begriff wird oft von Geschäftsanforderungen zitiert: Wenn Funktionen entwickelt werden, ist es wichtig, dass alte nicht kaputtgehen. Eine gut getestete Codebasis sollte dies beibehalten können. Echte Codebasen entsprechen jedoch nicht immer diesem Ideal. Dies wird in späteren Abschnitten noch genauer behandelt.

Visuelle Tests

Beim visuellen Testen werden Screenshots oder Videos vom Status einer Website erstellt, um einen bekanntermaßen fehlerfreien Zustand (z. B. einen vorherigen Screenshot) mit dem aktuellen Testlauf zu vergleichen. Aufgrund seiner Natur muss ein echter Browser ausgeführt werden, damit er HTML, CSS und andere Teile der Website rendern kann.

Anstelle von visuellen Tests von End-to-End-Tests, die die gesamte Codebasis ausführen, kann es nützlich sein, HTML-Typen zu erstellen, die nur bestimmte Komponenten rendern, insbesondere in unterschiedlichen Bildschirmgrößen, um responsive UIs auszulösen. Dies ist komplexer als die reine Verwendung von JSDOM oder ähnlichen Frameworks.

Fehlschlagende visuelle Tests können ein Anzeichen für andere Schäden sein. Komplexe UIs können bei visuellen Tests jedoch auch aus Gründen, die nichts mit den zu testenden Funktionen zu tun haben, fehlschlagen. Dazu gehören z. B. andere neue Funktionen, die das Aussehen der UI verändern, oder sogar eine neue Betriebssystemversion, die Emojis anders als frühere Versionen rendert.

End-to-End-Tests

End-to-End-Tests stehen oft ganz oben in der Testpyramide. Sie beschreiben eine umfassende Interaktion mit Ihrer Webanwendung oder Website, die sich um eine bestimmte Funktion dreht, und werden in der Regel in einem Browser ausgeführt, der von einem Agent wie WebdriverIO, Selenium oder Puppeteer gesteuert wird, der Ihre Codebasis mehr oder weniger ausführen kann, wie in der Produktion (obwohl sie oft auf localhost bereitgestellt werden).

Abhängig von Ihrer Website kann dies bedeuten, dass Sie sich als Testnutzer anmelden, wichtige Aktionen ausführen und prüfen, ob Ihre Website oder Ihr System im richtigen Zustand ist. In weiteren Abschnitten gehen wir auf weitere Beispiele für diese Art von Tests ein, da diese zwar sehr leistungsfähig, aber manchmal schwierig zu verwalten sind.

Zu den Taktiken zur Vereinfachung können die Reduzierung des Umfangs oder das Herausspielen bestimmter Komponenten, falls relevant, gehören. Wenn sich Nutzer beispielsweise auf Ihrer Website anmelden müssen, die Anmeldung aber nicht die Funktion ist, die Sie testen, können Sie ein Flag für Testumgebungen festlegen, das es dem Test-Controller ermöglicht, als Nutzer zu agieren, ohne sich anzumelden oder die zugehörigen Cookies zu erstellen.

Obwohl End-to-End-Tests sehr wirkungsvolle Möglichkeiten sein können, um große Querschnitte Ihrer Codebasis gleichzeitig zu testen, können solche umfangreichen Tests aufgrund ihrer Abhängigkeit von externen Systemen unzuverlässig oder unzuverlässig sein. Außerdem können sie viele Testdaten in Ihrer Datenbank belassen, wenn beispielsweise bei jedem Test ein Eintrag erstellt oder geändert wird. Wenn Restdaten wie diese gesammelt werden, kann es schwierig sein, zu bestimmen, wie ein Test fehlgeschlagen ist.

API-Tests

Mit API-Tests können Sie das Verhalten von APIs, die Ihre Software bereitstellt, oder auf reale (möglicherweise tatsächliche) APIs zugreifen, um deren Verhalten zu überprüfen. In beiden Fällen werden dabei die Abstraktionen zwischen Systemen getestet, d. h. wie sie letztendlich miteinander kommunizieren, ohne sie tatsächlich zusammen zu integrieren, wie in einem Integrationstest.

Diese Tests können eine einfache Vorstufe von Integrationstests sein, ohne dass die Ausführung der Systeme, zwischen denen Sie die Verbindungen testen, zu aufwendig sind. Tests von realen Systemen können jedoch instabil sein.

Sonstiges

Es gibt verschiedene andere Testansätze, die je nach Quelle nützlich sein können. Interessante Beispiele:

  • Manuelle Tests.
  • Akzeptanztests, eine Art von manuellen Tests, die bei Agile beliebt sind, bestätigt, dass das Produkt „die Bedürfnisse der Nutzenden erfüllt“.
  • Chaostests beziehen sich auf die Eingabe zufälliger Daten, um zu prüfen, was passiert, um sicherzustellen, dass eine Website nicht abstürzt, wenn fehlerhafte Daten eingegeben werden.
  • Fehlertests simulieren absichtlich Fehler in komplexen Systemen, z. B. Netzwerkfehler, um sicherzustellen, dass der zu testende Code kontrolliert reagiert.
  • Mit Build-Tests wird bestätigt, dass die Build-Artefakte einer Codebasis generiert werden können. Dazu wird geprüft, ob sie vorhanden sind oder welchen Inhalt sie haben. Mit diesem Testtyp können Sie die Ausgabe eines komplexen CMS überprüfen.

Codeabdeckung

Sie können messen, wie viel Prozent Ihres Codes durch automatisierte Tests getestet werden, und dies als Statistik im Zeitverlauf melden. Wir raten davon ab, eine Codeabdeckung von 100% anzustreben, da dies zu unnötigen Aufwand sowie zu vereinfachten oder schlecht konzipierten Tests führen kann, die die wichtigsten Anwendungsfälle nicht im Detail abdecken.

Die Abdeckung selbst kann auch ein nützliches Tool sein, wenn Sie Tests schreiben oder bearbeiten, insbesondere Integrationstests. Durch das Anzeigen eines Prozentsatzes oder einer zeilenweisen Aufschlüsselung dessen, welcher Code in einem einzelnen Test getestet wird, erhalten Sie Informationen dazu, was fehlt oder was als Nächstes getestet werden kann.

Ressourcen

Wissen testen

Welche der folgenden Testtypen sind bekannte Testtypen?

Visuelle Tests
Chaostests
Brandversuche
Vielleicht, wenn Sie Software für eine Feuerwehr entwickeln.
Differenzierungstests
Stresstests
Wir haben dies hier nicht erwähnt, aber Stress- oder Belastungstests sind eine Art von Produktionssystemen, mit der sichergestellt wird, dass sie eine große Menge an Traffic aufnehmen können. Es wird eher mit einem großen Systemdesign als mit dem Testen typischer Codebasis verbunden.