Welchen Wert hat es, zusätzliche Komponententests zu schreiben, wenn eine größere Funktion in kleinere Funktionen umgewandelt wird?

8

Wenn ich eine komplexe, auf Einheit getestete Funktion habe:

def do_everything():
    # turn twizzles
    # push buttons
    # move mountain

Und ich zerlege es in einige kleinere Einheiten:

def do_everything():
    turn_twizzles()
    push_buttons()
    move_mountain()

def turn_twizzles():
    # turn twizzles

def push_buttons():
    # push buttons

def move_mountain():
    # move mountain

Verschwende ich meine Zeit damit, zusätzliche Komponententests für diese kleineren Einheiten zu schreiben?

Adam Terrey
quelle

Antworten:

15

Ich nehme an, Sie haben bereits Unit-Tests zum Verhalten von do_everything()? Wenn Sie turn_twizzles()als private Methoden usw. ausgebrochen sind, haben Sie kein externes Verhalten geändert, sodass Sie keine Tests ändern müssen.

Wenn dies jedoch veröffentlicht turn_twizzles()wird, haben Sie eine neue Funktionalität eingeführt (wie von außerhalb der Klasse beobachtet), sodass es sinnvoll wäre, dies zu testen.

JacquesB
quelle
2
Ich bin mir nicht sicher, warum diese Antwort abgelehnt wurde. Es ist kurz, auf den Punkt und 100% genau in seiner Beratung.
David Arno
Dies ist eine sehr klare Antwort, danke. Ich denke, das Problem (Dank an @Samuel für die Erwähnung der Faust) ist das Problem des Wetters oder nicht, die öffentliche Oberfläche hat sich geändert.
Adam Terrey
Downvote, da dies nicht vollständig ist. Auch wenn die neuen Funktionen nicht Teil einer öffentlichen API waren, kann das Schreiben von Tests sehr hilfreich sein. Angenommen, ein Test für do_everything () schlägt fehl: Wo liegt der Fehler? Wenn Sie Tests für alle drei Unterfunktionen haben, ist es viel einfacher zu finden. Das ist ein Vorteil beim Schreiben der Tests und sollte hier erwähnt werden.
Marstato
1
@marstato: Es wird allgemein als schlechte Idee angesehen, private Methoden zu testen, da die Tests mit Implementierungsdetails gekoppelt werden.
JacquesB
@JaxquesB Das ist im Allgemeinen keine schlechte Sache. Man könnte sagen, dass alles, was präziser als ein gewöhnlicher Integrationstest ist, an Implementierungsdetails gebunden ist. Aber Sie schreiben diese Tests trotzdem, weil sie Ihnen helfen, Fehler zu verfolgen, und nicht, weil sie Ihnen helfen, die korrekte Funktionalität zu beweisen. Der Zugriffsmodifikator ist immer subjektiv. Ein privateSchlüsselwort in einer Programmiersprache ist nur eine von vielen Möglichkeiten, den Zugriff auf einen Code einzuschränken.
Marstato
12

Es hängt davon ab, ob. Genauer gesagt kommt es darauf an

  • die Komplexität der ursprünglichen Funktion (wenn sie sehr komplex war, zahlt es sich aus, jedes Teil einzeln zu testen)
  • die Komplexität der kleineren Funktionen (wenn es sich um komplexe Teile handelt, führt das individuelle Testen zu feinkörnigeren Tests und einer genaueren Erkennung der Grundursache im Falle eines Defekts)
  • die vorhandenen Komponententests (wenn sie bereits eine ausreichende Abdeckung für alle diese "Teile" ergeben, ist es wahrscheinlich weniger wert, einzelne Tests zu schreiben)
  • Wenn Sie diese kleineren Funktionen als "Implementierungsdetails" der ursprünglichen Funktionen beibehalten möchten oder nicht (bei ersteren wäre das Schreiben von Komponententests für die kleineren Funktionen für dieses Ziel kontraproduktiv).

Insbesondere wenn diese "kleineren Funktionen" nicht so trivial sind wie in Ihrem Beispiel, sondern eine mehr oder weniger komplexe Liste von Eingabeparametern enthalten, kann es sehr schwierig werden, genügend Komponententests für Ihre ursprüngliche Funktion zu erstellen, um sicherzustellen, dass die kleineren Funktionen getestet werden mit allen "interessanten" Eingabekombinationen. Das wäre ein klares Zeichen, um auch für die kleineren Funktionen spezifische Unit-Tests zu schreiben.

Es gibt also kein klares "Ja" oder "Nein" zu dieser Frage, es ist ein Kompromiss, den Sie pro Fall entscheiden müssen.

Doc Brown
quelle
6

Wenn turn_twizzles,, push_buttonsund move_mountainöffentlich sind und von anderem Code aufgerufen werden, ist es meiner Meinung nach wichtig, Ihre Tests zu überarbeiten, um diese Funktionen einzeln zu testen.

Leider nach dem Refactoring haben Sie ein Problem: In dem Unit - Test do_everythingmüssen Sie in der Lage sein , zu verhöhnen turn_twizzles, push_buttonsund move_mountain. Das Schreiben von Tests, do_everythingohne die Abhängigkeiten zu verspotten, ist ein Integrationstest - abhängig von Ihrem Testplan nicht unbedingt eine schlechte Sache, aber es bringt keinen großen Nutzen, da Sie die drei kleineren Funktionen bereits einzeln testen. Dies ist möglicherweise der richtige Zeitpunkt für Sie, um diese Komponente neu zu gestalten und mit anderen Objekten zusammenzuarbeiten, um die gesamte Arbeit von zu erledigen do_everything.

Wenn turn_twizzles, push_buttonsund move_mountainnicht extern aufgerufen werden, sollten sie als privat markiert werden, und ich würde nicht empfehlen, sie getrennt von zu testen do_everything. Dies liegt daran, dass aus einer von außen nach innen gerichteten Perspektive do_everythingdie kleinste Einheit wäre (weil die anderen nicht zugänglich sind). Lesen Sie auch diese Antwort zum Aufteilen von Methoden mit privaten Methoden.

Samuel
quelle
4
Ich habe dies als " zum Unit-Test do_everythingmuss man sich verspotten turn_twizzleskönnen push_buttons, und move_mountain... " herabgestuft, was von einer unsinnigen Definition von "Unit-Test" abhängt.
David Arno
1
@ David, um fair zu sein, Samuel erkennt das in der Antwort an. Art von.
GnP
4

Nein. Die zusätzlichen Unit-Tests sind genauer. Wenn dies move_mountainfehlschlägt, schlägt ein einzelner Test fehl, der genau angibt, was schief gelaufen ist.

Diese Präzision verkürzt die Debugging-Zeit, was wertvoll ist. Da der Test fokussierter ist, sollte er schneller ausgeführt werden als das Testen derselben Funktionalität über die volle Funktion, wodurch ein schnelleres Feedback bereitgestellt wird, was wertvoll ist.

Telastyn
quelle