Testcode kopieren und einfügen: Wie schlecht ist das?

12

Meine derzeitige Aufgabe besteht hauptsächlich darin, GUI-Testcode für verschiedene Anwendungen zu schreiben, an denen wir arbeiten. Ich finde jedoch, dass ich dazu neige, viel Code in Tests zu kopieren und einzufügen. Der Grund dafür ist, dass die Bereiche, die ich teste, in der Regel ähnlich genug sind, um wiederholt werden zu müssen, aber nicht ähnlich genug , um Code in Methoden oder Objekte zu kapseln. Ich finde, wenn ich versuche, Klassen oder Methoden ausgiebiger zu verwenden, werden Tests umständlicher zu warten und manchmal überhaupt erst schwer zu schreiben.

Stattdessen kopiere ich normalerweise einen großen Teil des Testcodes aus einem Abschnitt, füge ihn in einen anderen ein und nehme alle erforderlichen geringfügigen Änderungen vor. Ich verwende keine strukturierteren Codierungsmethoden, wie z. B. mehr OO-Prinzipien oder -Funktionen.

Fühlen sich andere Codierer beim Schreiben von Testcode so? Natürlich möchte ich den DRY- und YAGNI-Prinzipien folgen, aber ich finde, dass Testcode (automatisierter Testcode für GUI-Tests sowieso) es schwierig machen kann, diese Prinzipien zu befolgen. Oder brauche ich einfach mehr Codierungspraxis und ein besseres Gesamtsystem?

BEARBEITEN: Das Tool, das ich verwende, ist SilkTest, das in einer proprietären Sprache namens 4Test vorliegt. Außerdem sind diese Tests hauptsächlich für Windows-Desktopanwendungen gedacht, aber ich habe auch Webanwendungen mit diesem Setup getestet.

joshin4colours
quelle
Welches Testwerkzeug verwenden Sie? Möglicherweise unterstützt Ihr Testframework die von Ihnen geschriebenen Testtypen nicht. Das Ausschneiden und Einfügen von mehr als 3 Zeilen ist im Allgemeinen sehr schlecht. Wenn Sie jedoch durch die Automatisierung eines GUI-Tests deutlich mehr langfristigen Wert hinzufügen können als durch die manuelle Durchführung jedes Mal, ist alles, was Sie tun, wahrscheinlich verdammt gut.
GlenPeterson
Welche Sprache ist das auch? Möglicherweise steht Ihnen etwas zur Verfügung, das Ihnen nicht in den Sinn kommt und eine Wiederverwendung ermöglicht (wie erstklassige Funktionen). Auf der anderen Seite, Testfälle werden soll einfach gehalten werden, um es zu halten weniger wahrscheinlich haben sie Fehler selbst ...
Izkata
3
In allem, was ich geschrieben habe, ist das Testen von Code nicht vom Refactoring ausgeschlossen.
Simon Whitehead

Antworten:

23

Kopierte und dann bearbeitete Testfälle sind oft in Ordnung.

Tests sollten so wenig externe Abhängigkeiten wie möglich aufweisen und so einfach wie möglich sein. Testfälle ändern sich tendenziell mit der Zeit, und zuvor fast identische Testfälle können plötzlich voneinander abweichen. Das Aktualisieren eines Testfalls, ohne sich Gedanken über das Brechen anderer Fälle machen zu müssen, ist eine gute Sache.

Natürlich kann und sollte der Boilerplate-Code, der in vielen Testfällen identisch ist und sich gemeinsam ändern muss, herausgerechnet werden.

9000
quelle
1
So fühle ich mich hauptsächlich. Fast identischer Testcode ist in vielen Fällen in Ordnung, aber wiederholter identischer Testcode ist eine schlechte Nachricht.
Joshin4colours
12

Wiederholung ist die Wurzel allen Übels

Das ist richtig! Wiederholung ist die Wurzel allen Übels . Wahrscheinlich hat Knuth in seinem Buch gesagt: „Vorzeitige Optimierung ist die Wurzel allen Übels“, aber ich denke, es ist Wiederholung.

Wann immer Sie sich ein Programm ansehen oder eines schreiben und eine Wiederholung entdecken: Entfernen Sie es! Töte es sofort ... was auch immer, aber werde es los !

Jedes Mal, wenn ich eine Art Wiederholung einführte und dort einen Fehler beheben musste, vergaß ich, die Replik zu reparieren ... (Donald Knuth) Also, wenn es eine Wiederholung gibt, entfernen Sie sie einfach so gut wie möglich, hacken Sie nicht !

Stellen Sie sich ein sauberes, schlankes Design vor (z. B. das Einkapseln Ihrer sich wiederholenden Codeblöcke in Hilfsklassen) und schreiben Sie einige Tests, bevor Sie etwas ändern (nur um sicherzugehen, dass Sie nichts kaputt gemacht haben). Dies gilt für jeden Code, der geschrieben wird, und Testcodes sind keine Ausnahme.

Hier ist eine gute Lektüre von Code Horror, die mich inspiriert - Ein bescheidener Vorschlag für die Copy and Paste School of Code Reuse .

Yusubov
quelle
"Jedes Mal, wenn ich eine Art Wiederholung einführte und dort einen Fehler beheben musste, habe ich vergessen, das Replikat zu reparieren ..." genau. Wenn Sie c & p und vergessen, den kopierten Text an Ihren aktuellen Kontext anzupassen, kann dies sehr weh tun. Fehlerhafter Testcode klingt nicht nach der optimalen Situation, oder?
März
Ja, ich habe die Stationen von Knuth genommen :)
Yusubov
9
Sie haben sich wiederholt: Sie haben sich wiederholt, indem Sie im Titel und in Ihrem Intro-Satz gesagt haben: "Wiederholung ist die Wurzel allen Übels".
Thomas Eding
Ja, ich habe das absichtlich getan, um die Wichtigkeit zu betonen, und Sie können diesen Teil gerne bearbeiten :)
Yusubov
1
Thomas Eding, du hast dich auch wiederholt. Du hast dich auch wiederholt =)
marktani
7

Es ist immer noch ziemlich schlecht zu schneiden und einzufügen. Es gibt einige Probleme.

Ihre Tests sind möglicherweise spröde, da Sie für etwas anfällig sind, das eine Änderung des gesamten kopierten und eingefügten Codes erfordert. Müssen Sie alle Tests neu schreiben?

Wenn Sie die Logik außerhalb Ihrer Tests nicht in Hilfsmethoden einkapseln können, können Sie selbst keine Tests dieser Hilfsmethoden schreiben. Das Schreiben von Tests mit Testmethoden ist normalerweise zu schwierig, da Sie Ihren Code brechen müssen, um den Test zu testen. Sie können jedoch Hilfemethoden testen.

Dies kann dazu führen, dass die Tests weniger lesbar sind. Ein großer Block kopierten Codes ist möglicherweise schwerer zu lesen als ein Aufruf der Hilfsmethode mit einem beschreibenden Namen.

Alles, was ich aufgelistet habe, kann ein Problem sein. Wenn Sie keine von ihnen finden tatsächlich ist ein Problem , dann natürlich es ist in Ordnung.

psr
quelle
> Aufruf der Hilfsmethode mit einem beschreibenden Namen. Ist das nicht das Problem dabei, dass Ihre Unit-Tests jetzt zu Programmen für sich werden - was man vermeiden soll? Was ist, wenn einige Tests fehlschlagen? Ist der Code fehlerhaft oder die Testhelfer?
Dwjohnston
4

Ich habe dir immer zugestimmt. Aber im Laufe der Zeit stellte ich fest, dass jede Änderung, die ich vornahm (insbesondere DI-Änderungen bei Komponententests), zahlreiche Tests erforderte, um sich zu ändern, und das war umständlich. Jetzt abonniere ich die Schule von DRY, auch wenn ich Tests schreibe.

Für GUI-Tests sollten Sie sich das PageObject-Muster ansehen , um wiederholten Code zu reduzieren.

pdr
quelle
2

Ich würde empfehlen, XUnit-Muster aufzunehmen. Früher hatte ich genau das gleiche Problem, bis ich anfing, dieses Buch zu nutzen. Die Object Mutter Muster klingt wie es wäre das hilfreich für Ihr Szenario.

Wie bereits erwähnt, kann es schwierig sein, diesen Setup-Code ordnungsgemäß zu kapseln. Sie müssen ihn jedoch an allen Stellen ändern, die Sie kopieren und einfügen.

Michael Brown
quelle
+1 für den Object Mother patternallgemeinen Initialisierungscode.
k3b
2

Sollten Menschen versuchen, die Wiederholung einzuschränken, wenn sie können - ja. Die Auszahlung hängt jedoch von der Situation ab. Dies könnte auf die Debatte über bewährte Verfahren zurückgehen. Die Frage ist jedoch, was in dieser Situation für Sie am besten ist. Zu jeder Regel gibt es Ausnahmen.

Ein paar Dinge, die ich fragen würde, sind: 1) Wie wahrscheinlich ist es, dass sich diese in der UAT getestete Funktionalität ändert? Wenn es unwahrscheinlich ist, dass sich dies ändert, besteht eine geringere Wahrscheinlichkeit, dass Sie jeden Ihrer Codesätze aktualisieren müssen. 2) Wenn sich die UAT ändert, wirkt sich dies immer auf jeden Satz des kopierten Codes aus oder nur auf einen oder zwei Sätze? Wenn es isoliert sein kann und nur eine Änderung an einem Satz erforderlich ist, kann es hilfreich sein, die Dinge getrennt zu haben. 3) Wie komplex wird die ursprüngliche Methode sein, wenn Sie versuchen, alle Szenarien zu verarbeiten? Fügen Sie viele verschachtelte if / else / -Schleifen hinzu? Wenn Sie anfangen, die gesamte Verzweigung zu übertreiben, erhalten Sie möglicherweise Code, der schwer zu verstehen ist. Wäre es einfacher, die Aktualisierung in jedem kopierten Text vorzunehmen, als die gesamte Verzweigungslogik erneut zu überprüfen?

Wenn Sie beim Kopieren / Einfügen / Ändern nicht weiterkommen, sollten Sie Kommentare wie "Dies wird in Methode xyz kopiert" hinzufügen. Auf diese Weise werden Sie daran erinnert, alle eingefügten Versionen des Codes zu aktualisieren. Oder (von einem anderen SilkTest-Benutzer) Sie können eine separate inc-Datei hinzufügen, die sich nur auf diesen wiederholten Code konzentriert. Auf diese Weise haben Sie alle Variationen an einem Ort und können leicht die verschiedenen Methoden sehen, die aktualisiert werden müssten.

Dan B.
quelle
0

Ein großes Verfahren

Ein Gedanke: Es hört sich so an, als würden Sie versuchen, Code durch Ausschneiden und Einfügen zu vermeiden, indem Sie Methoden wie:

testScreen(title, fieldList, linkList, param1, param2, param3,...) {
    test that the layout at the top of the screen is correct
    test if PageTitle == title?
    for each field in fieldList:
        check that it appears in order on the screen
    for each field in linkList:
        check that it appears in order on the screen
    test if param1 is whatever...
    test if param2 is whatever...
    etc.
    test that the bottom of the screen is correct
}

Viele kleine Prozeduren (Toolkit)

Haben Sie auch den umgekehrten Ansatz in Betracht gezogen? Anstatt eine Million Parameter an eine große testScreen () -Prozedur zu übergeben, erstellen Sie möglicherweise Ihr eigenes Framework oder Toolkit mit kleinen Hilfsprozeduren, die Sie nach Bedarf erstellen. Mögen:

testScreenTop()
verifyLinks(list)
testScreenBottom()

Sie schneiden diese Prozeduren immer noch aus und fügen sie in jeden Bildschirm ein, aber Sie schneiden kleinere Codestücke aus und fügen sie ein und schneiden Gemeinsamkeitsblöcke heraus, die nicht ausgeschnitten und eingefügt werden (der Inhalt jeder kleinen Prozedur).

Ausschneiden und Einfügen

Das einzige Mal, dass mich ausgeschnittener und eingefügter Code nicht gebissen hat, war, als der Code weggeworfen wurde, bevor ich ihn ändern musste. Meine größte Sorge bei UI-Tests ist, wie schnell sie veraltet sind. Wenn Sie feststellen, dass Sie Ihren gesamten Code wegwerfen, bevor Sie ihn ändern, haben Sie möglicherweise eine Nische gefunden, in der das Ausschneiden und Einfügen in Ordnung ist! Es ist auch nicht so schlimm, wenn dem ausgeschnittenen und eingefügten Code kein Code nachgeschaltet ist (z. B. in der Benutzeroberfläche einer Anwendung). Wenn Sie mehr als 3 Zeilen einfügen, würde ich wirklich etwas dagegen unternehmen. Ergreifen Sie zumindest Maßnahmen, um dies zu minimieren!

Automatisierte UI-Tests

Wenn Sie mit automatisierten UI-Tests eine höhere Produktivität als mit manuellen Tests mit einer beliebigen Technik nachweisen können (die Kosten für das Schreiben / Verwalten automatisierter Tests sind jedes Mal niedriger als beim manuellen Testen, aber die Qualität ist gleich), sollten Sie ein Papier schreiben. Ich würde es lesen! Ich kann jetzt den Titel sehen: "Ausschneiden und Einfügen von Code ein Nettogewinn für UI-Tests!"

GlenPeterson
quelle
0

Es ist wirklich nicht so schlimm. Wenn Sie feststellen, dass bestimmte Codemuster sehr häufig verwendet werden und die Änderungen sehr routinemäßig sind (z. B. einige Zeichenfolgen oder Parameterwerte), können Sie sogar einen Codegenerator schreiben, der sich wiederholenden Testcode basierend auf einem kleinen (- ish?) Eingabeliste der Werte, die sich ändern. Ich habe dies (generierter Testcode) viele Male mit Batch-Dateien, SQLPlus-Skripten und sogar Excel-Makros gemacht (es klingt hässlich, aber die Variablen für die verschiedenen Testskripte waren bereits in einer Tabelle enthalten) und es kann eine große Zeitersparnis sein . Die Sache ist, dass Sie, wenn sich etwas an der Gesamtstruktur des sich wiederholenden Testfallcodes ändert, einfach alles neu generieren können, was Sie benötigen.

FrustratedWithFormsDesigner
quelle
0

Dies ist das gleiche wie bei den meisten anderen Antworten, jedoch auf eine Weise, die ein nicht technischer Manager verstehen kann.

Stellen Sie sich folgendes Fehlerszenario vor:

  • Jemand nimmt Änderungen an der Datenbanktabelle vor, von der viele Ihrer Tests abhängen.
  • Folge: Plötzlich schlagen 117 Ihrer 2933 automatisierten Tests fehl.

Was wirst du machen?

  • (1) 117 Tests reparieren?
  • (2) Löschen Sie die 117 Tests und implementieren Sie sie erneut durch Kopieren und Einfügen. Dies könnte einfacher sein als (1)
  • (3) Überarbeiten Sie die Tests, um gemeinsamen Code zu extrahieren, sodass Sie in Zukunft nur eine Methode (oder einige wenige) anpassen müssen, um die Tests zu korrigieren (siehe Antworten von @pdr oder @Michael Brown).
  • (4) Löschen Sie die 117 Tests, ohne die Tests erneut zu implementieren

Meiner Erfahrung nach:

Bei der Einführung automatisierter Tests mag das Management "Copy & Paste-Tests": Sie erhalten viele Tests in kurzer Zeit.

Nach einigen der "Fehlerszenarien" bevorzugt das Management (4), weil das Reparieren von "Copy & Paste-Tests" so teuer ist.

Richtig machen (3) wird nicht so schnell sein, erhöht aber die Überlebenschancen der Tests

k3b
quelle