Anders als bei Unit-Tests habt ihr bei End-to-End-Tests weniger Kontrolle über die Daten in eurem System und über eure Testumgebung. Hier sind ein paar Vorschläge, wie ihr eure Tests einfacher pflegen könnt, wenn sich die Daten oder die Testumgebung ändern:

  • Entkoppelt euch von bestehenden Testdaten. Geht nicht davon aus, dass eure Testdaten für immer in der DB existieren werden. Ich habe Tests gesehen, die sich auf DB-Daten aus der Produktion stützen, z. B. auf Benutzer mit bestimmten Namen oder Berechtigungen. Wenn Verweise auf diese Daten hart kodiert sind und die Daten hinter diesen Verweisen aktualisiert oder, noch schlimmer, entfernt werden, sind die Tests nutzlos. Lasst eure Tests stattdessen spezifische Testdaten erstellen oder ruft diese auf deklarative Weise ab, z. B. durch SQL-Abfragen.
  • Benennt eure Testdaten. Wenn ihr euch nicht für das Abrufen oder Erzeugen spezifischer Testdaten als Teil Ihres Tests entscheidet, gebt ihnen zumindest aussagekräftige Namen, die erklären, warum ihr diese und nicht eine andere Probe genommen habt. Stellt euch vor, ihr müsst den Testdatensatz mit Flügen pflegen, die nicht mehr aktuell sind: Es gibt keine Flüge mehr von Los Angeles nach Reykjavik. Ihr braucht also eine andere Stichprobe mit ähnlichen Flügen. Was bedeuten hier ähnliche Testdaten? D.h. Was war der Zweck der Tests für diesen speziellen Flug? Ging es darum, das Systemverhalten für einen Interkontinentalflug oder vielleicht für einen Hin- und Rückflug zu überprüfen? Ein besserer Weg wäre, diese Testdaten mit einem Namen zu versehen, z.B. anyIntercontinentalRoundtripFlight().
  • Entkoppelt von der Testumgebung. Macht eure Ihre Tests nicht an eine bestimmte Testumgebung gebunden. Ich habe schon Tests gesehen, in denen URLs, Pfade, DB-Verbindungs-URLs und andere umgebungsspezifische Elemente fest einkodiert waren. Wenn euer Produkt in einer neuen Konfiguration getestet werden muss, wird die Aktualisierung eurer Tests zu einem Alptraum. Trennt daher die Konfiguration der Testumgebung von euren Testfällen. Legt die Umgebungskonfiguration in separaten Klassen oder Dateien ab.

 

 

Die wenigen Regeln, die ich persönlich beim Entwurf automatisierter Tests befolge:

  • Vereinfacht euren Code: Vereinfacht euren Code so weit, dass er auf natürliche Weise von einer Schicht zur anderen fließt und von Dritten gelesen werden kann. Kann eine nicht-technische Person Ihren Code wie ein Buch lesen und verstehen (zumindest in den oberen Schichten)?
  • DRYup Ihres Codes: Trocknet euren Code aus, sodass ihr bei Änderungen nur an einer Stelle aktualisieren müsst. Führt immer wieder ein Refactoring durch, um den Code noch DRYer (Trockner) zu machen.
  • Entwerft robuste und flexible Locators: Diese sind kurz, eindeutig, aber flexibel genug, um schwer zu brechen zu sein.
  • Kleine fokussierte einfache Tests anstelle von langen komplexen Tests: Nur eine Assertion als letzten Schritt in einem Test haben.
  • Macht Tests unabhängig voneinander: Kein Test sollte fehlschlagen, nur weil ein anderer Test fehlgeschlagen ist.
  • Jeder Test sollte nur eine Sache testen: Jeder Test sollte nur aus einem Grund fehlschlagen; wenn ein Test aus mehreren Gründen fehlschlagen kann, ist er nicht richtig konzipiert.
  • Keine redundanten Schritte: Es sollte keine gleichen Schritte/Überprüfungspunkte geben, die in mehreren Tests abgedeckt werden.
  • Lokatoren und Testdaten entkoppeln: Isoliert Lokatoren und Testdaten vom Hauptautomatisierungscode, damit sie unabhängig aktualisiert werden können, ohne den Code zu berühren.

Behandelt Tests genauso wie euren sonstigen Code, verwendet Kodierungsrichtlinien, Entwicklungsmuster, bewährte Verfahren und dokumentiert Methoden usw... haltet sie aus der Sicht des Codes so wartbar wie möglich.

Um die Tests auf dem neuesten Stand zu halten, würde ich die folgenden Schritte zu Ihrem Prozess hinzufügen:

  • Lasst die Entwickler die Tests ausführen, bevor sie ihren Code einchecken/übertragen (macht sie dafür verantwortlich, dass automatisierte Tests nicht gebrochen werden)
  • Führt die Tests bei jedem Check-in/Commit mit einem Continuous Integration Server aus (damit ihr wisst, wer/was die Tests beschädigt hat).
  • Wenn ein Test fehlschlägt, ermittelt, ob es sich um einen Fehler handelt oder ob der Test aktualisiert werden muss.
    Stellt sicher, dass jemand an der Behebung des Fehlers arbeitet, bevor ihr die Entwicklung fortsetzt.
    Der Schlüssel ist, dem Entwickler so schnell wie möglich Feedback zu geben und zu verhindern, dass er auf Treibsand baut.