Legen Sie fest, was Sie testen müssen und was Sie ausschließen können.
Im vorherigen Artikel haben wir die Grundlagen von Testfällen und ihre Inhalte behandelt. In diesem Artikel wird das Erstellen von Testfällen aus technischer Sicht genauer erläutert. Außerdem erfahren Sie, was in jedem Test enthalten sein sollte und was Sie vermeiden sollten. Im Grunde erfahren Sie die Antwort auf die uralte Frage „Was soll getestet werden?“ oder „Was soll nicht getestet werden?“.
Allgemeine Richtlinien und Muster
Bestimmte Muster und Punkte sind unabhängig davon entscheidend, ob Sie Unit-, Integrations- oder End-to-End-Tests durchführen. Diese Prinzipien können und sollten auf beide Arten von Tests angewendet werden. Sie sind also ein guter Ausgangspunkt.
So einfach wie möglich
Beim Schreiben von Tests ist es wichtig, es einfach zu halten. Es ist wichtig, die Kapazität des Gehirns zu berücksichtigen. Der Hauptproduktionscode nimmt viel Platz ein, sodass nur wenig Raum für zusätzliche Komplexität bleibt. Das gilt insbesondere für Tests.
Wenn weniger Platz zur Verfügung steht, können Sie bei Ihren Tests entspannter vorgehen. Deshalb ist es wichtig, bei Tests auf Einfachheit zu achten. In den Best Practices für JavaScript-Tests von Yoni Goldberg wird die Bedeutung der goldenen Regel hervorgehoben: Ihr Test sollte sich wie ein Assistent und nicht wie eine komplexe mathematische Formel anfühlen. Mit anderen Worten: Sie sollten die Absicht Ihres Tests auf den ersten Blick verstehen können.
Sie sollten bei allen Arten von Tests auf Einfachheit achten, unabhängig von ihrer Komplexität. Je komplexer ein Test ist, desto wichtiger ist es, ihn zu vereinfachen. Eine Möglichkeit besteht in einem einfachen Testdesign, bei dem die Tests so einfach wie möglich gehalten werden und nur das getestet wird, was unbedingt erforderlich ist. Das bedeutet, dass jeder Test nur einen Testfall enthalten sollte und sich der Testfall auf das Testen einer einzelnen, bestimmten Funktion oder eines bestimmten Features konzentrieren sollte.
Sehen Sie es so: Es sollte leicht zu erkennen sein, was bei einem fehlgeschlagenen Test schiefgelaufen ist. Daher ist es wichtig, Tests einfach und leicht verständlich zu gestalten. So können Sie Probleme schnell erkennen und beheben, wenn sie auftreten.
Testen, was sich lohnt
Das flache Testdesign fördert außerdem den Fokus und trägt dazu bei, dass Ihre Tests aussagekräftig sind. Denken Sie daran, dass Sie keine Tests nur zur Abdeckung erstellen sollten. Sie sollten immer einen Zweck haben.
Implementierungsdetails nicht testen
Ein häufiges Problem bei Tests besteht darin, dass sie oft auf die Prüfung von Implementierungsdetails ausgerichtet sind, z. B. die Verwendung von Auswahlschaltern in Komponenten oder End-to-End-Tests. Implementierungsdetails beziehen sich auf Dinge, die Nutzer Ihres Codes normalerweise nicht verwenden, sehen oder sogar kennen. Dies kann zu zwei großen Problemen bei Tests führen: falsch negative und falsch positive Ergebnisse.
Falsch-negative Ergebnisse treten auf, wenn ein Test fehlschlägt, obwohl der getestete Code korrekt ist. Das kann passieren, wenn sich die Implementierungsdetails aufgrund eines Refaktorings des Anwendungscodes ändern. Falsch-positive Ergebnisse treten dagegen auf, wenn ein Test bestanden wird, obwohl der getestete Code falsch ist.
Eine Lösung für dieses Problem besteht darin, die verschiedenen Nutzertypen zu berücksichtigen. Endnutzer und Entwickler können sich in ihrem Ansatz unterscheiden und möglicherweise unterschiedlich mit dem Code interagieren. Bei der Planung von Tests ist es wichtig, zu berücksichtigen, was Nutzer sehen oder mit was sie interagieren werden, und die Tests von diesen Dingen abhängig zu machen, anstatt von den Implementierungsdetails.
Wenn Sie beispielsweise Selektoren auswählen, die weniger anfällig für Änderungen sind, können Tests zuverlässiger werden: Datenattribute anstelle von CSS-Selektoren. Weitere Informationen finden Sie unter Kent C. Artikel von Dodds zu diesem Thema oder warten Sie einfach auf einen Artikel zu diesem Thema, der demnächst erscheint.
Mocking: Nicht die Kontrolle verlieren
Mocking ist ein umfassendes Konzept, das in Unit-Tests und manchmal auch in Integrationstests verwendet wird. Dabei werden gefälschte Daten oder Komponenten erstellt, um Abhängigkeiten zu simulieren, die die Anwendung vollständig steuern. So können Sie isolierte Tests durchführen.
Die Verwendung von Mockups in Ihren Tests kann die Vorhersagbarkeit, die Trennung von Aufgaben und die Leistung verbessern. Wenn Sie einen Test durchführen müssen, der menschliches Eingreifen erfordert (z. B. die Überprüfung eines Reisepasses), müssen Sie ihn mit einem Mockup verbergen. Aus all diesen Gründen sind Mockups ein wertvolles Tool.
Gleichzeitig kann sich das Mocking auf die Genauigkeit des Tests auswirken, da es sich um Mockups handelt und nicht um die tatsächliche Nutzererfahrung. Daher sollten Sie bei der Verwendung von Mockups und Stubs vorsichtig sein.
Sollten Sie in End-to-End-Tests Mockups verwenden?
Im Allgemeinen nicht. Mockups können jedoch manchmal ein Lebensretter sein – also sollten wir sie nicht komplett ausschließen.
Stellen Sie sich folgendes Szenario vor: Sie schreiben einen Test für eine Funktion, die den Dienst eines Zahlungsanbieters umfasst. Sie befinden sich in einer von ihnen bereitgestellten Sandbox-Umgebung, d. h. es finden keine echten Transaktionen statt. Leider funktioniert die Sandbox nicht richtig, was dazu führt, dass Ihre Tests fehlschlagen. Die Behebung muss vom Zahlungsanbieter erfolgen. Sie können nur warten, bis das Problem vom Anbieter behoben wird.
In diesem Fall ist es möglicherweise sinnvoller, die Abhängigkeit von Diensten zu verringern, die Sie nicht steuern können. Es ist jedoch ratsam, Mockups bei Integrations- oder End-to-End-Tests mit Bedacht zu verwenden, da dadurch das Konfidenzniveau Ihrer Tests sinkt.
Testspezifische Hinweise: Was Sie tun und was Sie vermeiden sollten
Was enthält ein Test also insgesamt? Gibt es Unterschiede zwischen den Testtypen? Sehen wir uns einige spezifische Aspekte an, die auf die Haupttesttypen zugeschnitten sind.
Was gehört zu einem guten Unit-Test?
Ein idealer und effektiver Unit-Test sollte:
- Konzentrieren Sie sich auf bestimmte Aspekte.
- Sie arbeiten unabhängig voneinander.
- Sie umfassen kleine Szenarien.
- Verwenden Sie aussagekräftige Namen.
- Folgen Sie gegebenenfalls dem AAA-Muster.
- Umfassende Testabdeckung gewährleisten.
Empfohlen ✅ | Nicht empfohlen ❌ |
---|---|
Halten Sie die Tests so klein wie möglich. Testen Sie jeweils eine Sache pro Testfall. | Schreiben Sie Tests für große Einheiten. |
Halten Sie Tests immer isoliert und simulieren Sie die Dinge, die Sie benötigen und die sich außerhalb Ihrer Einheit befinden. | Andere Komponenten oder Dienste einschließen |
Halten Sie die Tests unabhängig. | Sie können auf frühere Tests zurückgreifen oder Testdaten teilen. |
Verschiedene Szenarien und Pfade abdecken | Beschränken Sie sich auf den Happy Path oder maximal auf negative Tests. |
Verwenden Sie aussagekräftige Testtitel, damit Sie sofort sehen können, worum es bei Ihrem Test geht. | Test nur nach Funktionsnamen, daher nicht prägnant genug: testBuildFoo() oder testGetId() . |
Streben Sie in dieser Phase eine gute Codeabdeckung oder eine größere Auswahl an Testfällen an. | Testen Sie von jeder Klasse bis hinunter zur Datenbankebene (E/A). |
Was gehört zu einem guten Integrationstest?
Ein idealer Integrationstest teilt einige Kriterien mit Einheitentests. Es gibt jedoch noch einige weitere Punkte, die Sie berücksichtigen müssen. Ein guter Integrationstest sollte:
- Interaktionen zwischen Komponenten simulieren.
- Achten Sie darauf, dass Sie reale Szenarien abdecken und Mockups oder Stubs verwenden.
- Berücksichtigen Sie die Leistung.
Empfohlen ✅ | Nicht empfohlen ❌ |
---|---|
Integrationspunkte testen: Prüfen Sie, ob die einzelnen Einheiten zusammen reibungslos funktionieren. | Testen Sie jede Einheit einzeln – dazu sind Unittests da. |
Testen Sie reale Szenarien: Verwenden Sie Testdaten, die aus realen Daten abgeleitet wurden. | Wiederholbare automatisch generierte Testdaten oder andere Daten verwenden, die keine realen Anwendungsfälle widerspiegeln |
Verwenden Sie Mocks und Stubs für externe Abhängigkeiten, um die Kontrolle über den gesamten Test zu behalten. | Abhängigkeiten von Drittanbieterdiensten schaffen, z. B. Netzwerkanfragen an externe Dienste |
Verwenden Sie vor und nach jedem Test eine Bereinigungsroutine. | Wenn Sie keine Maßnahmen zur Bereinigung in Ihren Tests verwenden, kann dies aufgrund fehlender korrekter Testisolierung zu Testfehlern oder falsch positiven Ergebnissen führen. |
Was gehört zu einem guten End-to-End-Test?
Ein umfassender End-to-End-Test sollte:
- Nutzerinteraktionen nachahmen
- Umfassen Sie wichtige Szenarien.
- Mehrere Ebenen abdecken.
- Asynchrone Vorgänge verwalten
- Prüfen Sie die Ergebnisse.
- Berücksichtigen Sie die Leistung.
Empfohlen ✅ | Nicht empfohlen ❌ |
---|---|
API-basierte Verknüpfungen verwenden Weitere Informationen | Verwenden Sie für jeden Schritt UI-Interaktionen, einschließlich des beforeEach -Hooks. |
Führen Sie vor jedem Test eine Bereinigung durch. Achten Sie bei der Testisolation noch sorgfältiger als bei Unit- und Integrationstests darauf, da hier ein höheres Risiko für Nebenwirkungen besteht. | Sie vergessen, nach jedem Test aufzuräumen. Wenn Sie den verbleibenden Status, die Daten oder die Nebenwirkungen nicht bereinigen, wirken sich diese auf andere Tests aus, die später ausgeführt werden. |
Betrachten Sie End-to-End-Tests als Systemtests. Das bedeutet, dass Sie den gesamten Anwendungsstack testen müssen. | Testen Sie jede Einheit einzeln – dazu sind Unittests da. |
Verwenden Sie im Test möglichst wenig oder gar kein Mocking. Überlegen Sie sich gut, ob Sie externe Abhängigkeiten simulieren möchten. | Setzen Sie stark auf Mockups. |
Berücksichtigen Sie Leistung und Arbeitslast, indem Sie beispielsweise nicht zu viele große Szenarien im selben Test testen. | Große Workflows abdecken, ohne Verknüpfungen zu verwenden |