it-swarm.com.de

Ist es sinnvoll, keine Komponententests zu schreiben, weil sie später auskommentiert werden oder weil Integrationstests wertvoller sind?

Ich habe mit einem Kollegen über Unit-/Integrationstests gesprochen, und er hat einen interessanten Fall gemacht gegen Unit-Tests schreiben. Ich bin ein großer Befürworter von Unit-Tests (hauptsächlich JUnit), aber ich bin daran interessiert, die Einstellungen anderer zu hören, da er einige interessante Punkte hervorgehoben hat.

Um seine Punkte zusammenzufassen:

  • Wenn größere Codeänderungen auftreten (neue POJOs, größere Umgestaltung von Anwendungen usw.), werden Komponententests eher auskommentiert als überarbeitet.
  • Die Zeit wird besser für Integrationstests aufgewendet, die Anwendungsfälle abdecken, wodurch die Tests mit kleinerem Umfang weniger oder gar nicht wichtig werden.

Gedanken dazu? Ich bin immer noch ein Pro-Unit-Test (da ich immer wieder sehe, dass er verbesserten Code erzeugt), obwohl Integrationstests mindestens genauso wertvoll klingen.

35
Jeff Levine

Ich neige dazu, auf der Seite Ihres Freundes zu stehen, weil nit-Tests testen allzu oft die falschen Dinge.

Unit-Tests sind nicht von Natur aus schlecht. Sie testen jedoch häufig eher die Implementierungsdetails als den Eingabe-/Ausgabefluss. In diesem Fall werden Sie völlig sinnlos getestet. Meine eigene Regel lautet: Ein guter Komponententest sagt Ihnen, dass Sie gerade etwas kaputt gemacht haben; ein schlechter Komponententest sagt Ihnen nur, dass Sie gerade etwas geändert haben.

Ein Beispiel aus dem Kopf ist ein Test, der vor ein paar Jahren in WordPress) gesteckt wurde. Die getestete Funktionalität drehte sich um Filter, die sich gegenseitig anriefen, und die Tests bestätigten, dass Rückrufe dies tun würden Dann werden Sie in der richtigen Reihenfolge aufgerufen. Anstatt (a) die Kette auszuführen, um zu überprüfen, ob Rückrufe in der erwarteten Reihenfolge aufgerufen werden, konzentrierten sich die Tests darauf, (b) einen internen Status zu lesen, der von Anfang an wohl nicht hätte offengelegt werden dürfen Ändern Sie die Einbauten und (b) wird rot, während (a) nur rot wird, wenn Änderungen an den Einbauten das erwartete Ergebnis brechen. (B) war aus meiner Sicht eindeutig ein sinnloser Test.

Wenn Sie eine Klasse haben, die einige Methoden der Außenwelt zugänglich macht, sollten Sie meiner Ansicht nach nur die letzteren Methoden testen.) . Wenn Sie auch die interne Logik testen, können Sie die interne Logik der Außenwelt aussetzen, indem Sie verschlungene Testmethoden verwenden oder eine Litanei von Komponententests verwenden, die immer dann unterbrochen werden, wenn Sie etwas ändern möchten.

Nach alledem wäre ich überrascht, wenn Ihr Freund Unit-Tests per se genauso kritisch gegenübersteht, wie Sie vermuten. Ich würde eher sagen, dass er pragmatisch ist. Das heißt, er stellte fest, dass die Unit-Tests, die geschrieben werden, in der Praxis meist sinnlos sind. Zitat: "Unit-Tests werden eher auskommentiert als überarbeitet". Für mich gibt es dort eine implizite Botschaft - wenn sie dazu neigen, überarbeitet zu werden, dann weil sie dazu neigen, zu saugen. Unter der Annahme folgt der zweite Satz: Entwickler würden weniger Zeit damit verschwenden, Code zu schreiben, der schwerer zu verwechseln ist - d. H. Integrationstests.

Als solches geht es nicht darum, dass jemand besser oder schlechter ist. Es ist nur so, dass man viel leichter falsch liegen kann und in der Praxis sogar sehr oft falsch liegt.

62

Wenn größere Codeänderungen auftreten, werden Komponententests eher auskommentiert als überarbeitet.

Mit einer undisziplinierten Gruppe von Cowboy-Programmierern, die glauben, dass alle Tests "grün" werden, wenn Sie alle vorhandenen Tests auskommentieren: natürlich. Das Überarbeiten von Unit-Tests erfordert die gleiche Disziplin wie das Schreiben aus erster Hand. Sie müssen hier also an der "Definition von erledigt" Ihres Teams arbeiten.

Die Zeit wird besser für Integrationstests aufgewendet, die Anwendungsfälle abdecken, bei denen die Tests mit kleinerem Umfang weniger oder gar nicht wichtig sind.

Das ist weder völlig falsch noch völlig richtig. Der Aufwand für das Schreiben nützlicher Integrationstests hängt stark davon ab, welche Art von Software Sie schreiben. Wenn Sie eine Software haben, mit der Integrationstests fast so einfach geschrieben werden können wie Komponententests, die immer noch schnell ausgeführt werden und Ihnen eine gute Abdeckung Ihres Codes bieten, dann hat Ihr Kollege Recht. Aber für viele Systeme, die ich gesehen habe, können diese drei Punkte durch Integrationstests nicht einfach erfüllt werden. Deshalb sollten Sie sich bemühen, auch Komponententests durchzuführen.

38
Doc Brown

Ich weiß nicht, dass ich die Argumente Ihres Kollegen akzeptiere.

  1. Wenn Unit-Tests auskommentiert werden, liegt das daran, dass jemand faul ist. Das ist nicht die Schuld der Unit-Tests. Und wenn Sie anfangen, Faulheit als Ausrede zu benutzen, können Sie gegen fast jede Praxis argumentieren, die ein wenig Mühe erfordert.
  2. Wenn Sie es richtig machen, müssen Unit-Tests nicht lange dauern. Sie hindern Sie nicht daran, wichtigere Arbeit zu leisten. Wenn wir uns alle einig sind, dass das Beheben von fehlerhaftem Code wichtiger ist als alles andere, ist ein Komponententest verdammt wichtig. Es ist eine einfache Möglichkeit, die Post-Bedingungen zu testen. Woher wissen Sie, dass Sie ohne sie die Post-Zustandsgarantien erfüllt haben? Und wenn nicht, ist Ihr Code kaputt.

Es gibt andere, überzeugendere Argumente gegen Unit-Tests. Nun, nicht gerade gegen sie. Beginnen Sie mit DHHs Test-induzierter Designschaden . Er ist ein lustiger Schriftsteller, also lies es. Was ich daraus genommen habe:

Wenn Sie große Designänderungen vornehmen, um Ihre Komponententests zu berücksichtigen, können diese andere Ziele in Ihrem Projekt beeinträchtigen. Fragen Sie nach Möglichkeit eine unparteiische Person, welcher Ansatz leichter zu befolgen ist. Wenn Ihr hoch testbarer Code schwer zu verstehen ist, verlieren Sie möglicherweise alle Vorteile, die Sie durch Unit-Tests erzielt haben. Der kognitive Aufwand von zu viel Abstraktion verlangsamt Sie und erleichtert undichte Fehler. Diskontiere es nicht.

Wenn Sie nuanciert und philosophisch werden möchten, gibt es viele großartige Ressourcen:

13
Scant Roger

Wenn größere Codeänderungen auftreten (neue POJOs, größere Umgestaltung von Anwendungen usw.), werden Komponententests eher auskommentiert als überarbeitet.

Tu das nicht. Wenn Sie jemanden finden, der das tut, ermorden Sie ihn und stellen Sie sicher, dass er sich nicht vermehrt, da seine Kinder dieses defekte Gen möglicherweise erben. Der Schlüssel, wie ich es beim Anschauen von CSI-Fernsehsendungen sehe, besteht darin, viele irreführende DNA-Proben überall zu verteilen. Auf diese Weise verschmutzen Sie den Tatort mit so viel Lärm, dass angesichts der kostspieligen und zeitaufwändigen Natur von DNA-Tests die Wahrscheinlichkeit, dass sie an Sie gebunden werden, astronomisch gering ist.

6
user204677

unit-Tests werden eher auskommentiert als überarbeitet.

Zu diesem Zeitpunkt lautet der Codeüberprüfungsprozess "Fix the Unit Tests" und dies ist kein Problem mehr :-) Wenn Ihr Codeüberprüfungsprozess diese Art von schwerwiegendem Fehler im übermittelten Code nicht erkennt, ist dies das Problem.

4
Philip Kendall

Wenn größere Codeänderungen auftreten (neue POJOs, größere Umgestaltung von Anwendungen usw.), werden Komponententests eher auskommentiert als überarbeitet.

Ich versuche immer, Refactoring und Funktionsänderung getrennt zu halten. Wenn ich beides tun muss, lege ich normalerweise zuerst das Refactoring fest.

Beim Refactoring von Code ohne Änderung der Funktionalität sollen vorhandene Komponententests sicherstellen, dass das Refactoring die Funktionalität nicht versehentlich beeinträchtigt. Für ein solches Commit würde ich das Deaktivieren oder Entfernen von Komponententests als ein wichtiges Warnzeichen betrachten. Jeder Entwickler, der dies tut, sollte angewiesen werden, dies nicht zu tun, wenn der Code überprüft wird.

Es ist möglich, dass Änderungen, die die Funktionalität nicht ändern, dazu führen, dass Komponententests aufgrund fehlerhafter Komponententests immer noch fehlschlagen. Wenn Sie den Code verstehen, den Sie ändern, ist die Ursache für solche Unit-Test-Fehler normalerweise sofort offensichtlich und leicht zu beheben.

Wenn eine Funktion beispielsweise drei Argumente akzeptiert, hat ein Komponententest, der die Interaktion zwischen den ersten beiden Argumenten für die Funktion abdeckt, möglicherweise nicht darauf geachtet, einen gültigen Wert für das dritte Argument bereitzustellen. Dieser Fehler im Komponententest kann durch ein Refactoring des getesteten Codes aufgedeckt werden, ist jedoch leicht zu beheben, wenn Sie verstehen, was der Code tun soll und was der Komponententest testet.

Wenn Sie vorhandene Funktionen ändern, müssen Sie normalerweise auch einige Komponententests ändern. In diesem Fall stellen Unit-Tests sicher, dass Ihr Code die Funktionalität wie beabsichtigt ändert und keine unbeabsichtigten Nebenwirkungen hat.

Wenn Sie Fehler beheben oder neue Funktionen hinzufügen, müssen Sie normalerweise weitere Komponententests hinzufügen. Für diese kann es hilfreich sein, zuerst Komponententests und später die Fehlerbehebung oder neue Funktionen festzuschreiben. Dies erleichtert die Überprüfung, ob die neuen Komponententests nicht mit dem älteren Code, sondern mit dem neueren Code bestanden wurden. Dieser Ansatz ist jedoch nicht ganz ohne Nachteile, so dass es auch Argumente dafür gibt, sowohl neue Komponententests als auch Codeaktualisierungen gleichzeitig durchzuführen.

Die Zeit wird besser für Integrationstests aufgewendet, die Anwendungsfälle abdecken, wodurch die Tests mit kleinerem Umfang weniger oder gar nicht wichtig werden.

Darin liegt ein Element der Wahrheit. Wenn Sie die unteren Ebenen des Software-Stacks mit Tests abdecken können, die auf die höheren Ebenen des Software-Stacks abzielen, sind Ihre Tests möglicherweise hilfreicher, wenn Sie Code umgestalten.

Ich glaube nicht, dass Sie eine Einigung über die genaue Unterscheidung zwischen einem Komponententest und einem Integrationstest finden werden. Und ich würde mir keine Sorgen machen, wenn Sie einen Testfall haben, den ein Entwickler als Komponententest und ein anderer als Integrationstest bezeichnet, sofern er zustimmen kann, dass es sich um einen nützlichen Testfall handelt.

3
kasperd

Integrationstests werden durchgeführt, um zu überprüfen, ob sich das System so verhält, wie es soll, was immer geschäftlichen Wert hat. Unit-Tests machen das nicht immer. Unit-Tests könnten beispielsweise toten Code testen.

Es gibt eine Testphilosophie, die besagt, dass jeder Test, der Ihnen keine Informationen liefert, eine Verschwendung ist. Wenn an einem Code nicht gearbeitet wird, werden seine Komponententests immer (oder fast immer) grün sein und Ihnen nur wenige oder gar keine Informationen geben.

Jede Testmethode ist unvollständig. Selbst wenn Sie eine 100% ige Abdeckung durch eine Metrik erhalten, durchlaufen Sie nicht nahezu alle möglichen Eingabedaten. Denken Sie also nicht, dass Unit-Tests magisch sind.

Ich habe oft die Behauptung gesehen, dass Unit-Tests Ihren Code verbessern. Meiner Meinung nach zwingen die Verbesserungen, die Unit-Tests zum Code bringen, Leute, die nicht daran gewöhnt sind, dazu, ihren Code in kleine, gut faktorisierte Teile zu zerlegen. Wenn Sie sich daran gewöhnen, Ihren Code normalerweise in kleinen, gut faktorisierten Teilen zu entwerfen, müssen Sie möglicherweise keine Komponententests mehr durchführen, um dies zu erzwingen.

Abhängig davon, wie stark Sie Unit-Tests durchführen und wie groß Ihr Programm ist, kann es zu einer enormen Anzahl von Unit-Tests kommen. Wenn ja, werden große Veränderungen schwieriger. Wenn eine große Änderung viele fehlgeschlagene Komponententests verursacht, können Sie die Änderung ablehnen, viel Arbeit leisten, um viele Tests zu reparieren, oder die Tests wegwerfen. Keine der Entscheidungen ist ideal.

Unit-Tests sind ein Werkzeug in der Toolbox. Sie sind da, um dir zu dienen, nicht umgekehrt. Stellen Sie sicher, dass Sie mindestens so viel aus ihnen herausholen, wie Sie hineingesteckt haben.

3
Michael Shaw

Unit Test sind definitiv nicht die Silberkugel, die manche Befürworter für sie halten. Im Allgemeinen weisen sie jedoch ein sehr positives Kosten-Nutzen-Verhältnis auf. Sie werden Ihren Code nicht "besser" machen, vielleicht modularer. "besser" hat so viel mehr Faktoren als "Testbarkeit" impliziert. Aber sie werden sicherstellen, dass es in allen Fällen und Verwendungen funktioniert, über die Sie nachgedacht haben, und die meisten Ihrer Fehler (wahrscheinlich die trivialeren) beseitigen.

Der größte Vorteil von Komponententests besteht jedoch darin, dass Ihr Code flexibler und widerstandsfähiger gegenüber Änderungen ist. Sie können Funktionen umgestalten oder hinzufügen und ziemlich sicher sein, dass Sie nichts kaputt gemacht haben. Dies allein macht sie für die meisten Projekte lohnenswert.

Bezugnehmend auf die Punkte Ihres Freundes:

  1. Wenn das Hinzufügen von POJOs Ihre Komponententests unterbricht, sind sie wahrscheinlich sehr schlecht geschrieben. POJOs sind normalerweise die Sprache, in der Sie über Ihre Domain sprechen, und die Probleme, die Sie lösen. Wenn Sie sie ändern, bedeutet dies offensichtlich, dass sich Ihre gesamte Geschäftslogik und wahrscheinlich der Präsentationscode ändern müssen. Sie können nicht erwarten, dass sich durch die Sicherstellung, dass diese Teile Ihres Programms funktionieren, nichts ändert ...

  2. Sich zu beschweren, dass Unit-Tests schlecht sind, weil die Leute sie auskommentieren, ist wie sich zu beschweren, dass Sicherheitsgurte schlecht sind, weil die Leute sie nicht tragen. Wenn man das Testen von Code auskommentiert und etwas kaputt macht, sollte man in ein sehr ernstes und unangenehmes Gespräch mit seinem Chef geraten ...

  3. Integrationstests sind Unit-Tests weit überlegen. keine Frage. vor allem, wenn Sie ein Produkt testen. Es ist jedoch unglaublich schwierig, gute, umfassende Integrationstests zu schreiben, die Ihnen den gleichen Wert, die gleiche Abdeckung und die gleiche Richtigkeit bieten, die Ihnen Unit-Tests bieten.

3
AK_

Ich kann mir nur ein Argument gegen Unit-Tests vorstellen, und es ist ziemlich schwach.

Unit-Tests zeigen den größten Teil ihres Werts, wenn Sie den Code zu einem späteren Zeitpunkt umgestalten oder ändern. Sie sehen eine enorme Reduzierung der Zeit, die zum Hinzufügen von Funktionen erforderlich ist, und stellen sicher, dass Sie nichts kaputt gemacht haben.

Allerdings: Das Schreiben von Tests ist in erster Linie mit (geringen) Kosten verbunden.

Deshalb: Wenn ein Projekt kurz genug ist und keine laufenden Wartungs-/Aktualisierungsarbeiten erfordert, überwiegen möglicherweise die Kosten für das Schreiben von Tests deren Vorteile.

2
Ewan