(Warum) ist es wichtig, dass ein Komponententest keine Abhängigkeiten testet?

103

Ich verstehe den Wert des automatisierten Testens und setze es überall dort ein, wo das Problem genau genug spezifiziert ist, um mir gute Testfälle einfallen zu lassen. Ich habe jedoch bemerkt, dass einige Leute hier und auf StackOverflow das Testen nur einer Einheit betonen , nicht ihrer Abhängigkeiten. Hier sehe ich den Nutzen nicht.

Das Verspotten / Stubben, um Testabhängigkeiten zu vermeiden, erhöht die Komplexität der Tests. Es fügt Ihrem Produktionscode künstliche Flexibilität / Entkopplungsanforderungen hinzu, um das Verspotten zu unterstützen. (Ich bin mit niemandem einverstanden, der meint, dies fördere gutes Design. Das Schreiben von zusätzlichem Code, das Einführen von Abhängigkeiten-Injection-Frameworks oder das Hinzufügen von Komplexität zu Ihrer Codebasis, um Dinge flexibler / steckbarer / erweiterbarer / entkoppelter zu machen, ohne einen echten Anwendungsfall, ist Überentwicklung, nicht gutes Design.)

Zweitens bedeutet das Testen von Abhängigkeiten, dass kritischer Low-Level-Code, der überall verwendet wird, mit anderen Eingaben getestet wird als denen, an die derjenige, der die Tests geschrieben hat, explizit gedacht hat. Ich habe viele Fehler in der Low-Level-Funktionalität gefunden, indem ich Unit-Tests mit High-Level-Funktionalität durchgeführt habe, ohne die Low-Level-Funktionalität, von der sie abhing, zu verfälschen. Im Idealfall wurden diese bei den Unit-Tests für die Low-Level-Funktionalität gefunden, es kommt jedoch immer zu Ausfällen.

Was ist die andere Seite davon? Ist es wirklich wichtig, dass ein Unit-Test nicht auch seine Abhängigkeiten testet? Wenn ja warum?

Bearbeiten: Ich kann den Wert des Verspottens von externen Abhängigkeiten wie Datenbanken, Netzwerken, Webdiensten usw. verstehen . (Dank an Anna Lear, die mich dazu motiviert hat, dies zu klären.) Ich bezog mich auf interne Abhängigkeiten , dh andere Klassen, statische Funktionen usw. das hat keine direkten externen Abhängigkeiten.

dsimcha
quelle
14
"Überentwicklung, kein gutes Design". Sie müssen mehr Beweise dafür vorlegen. Viele Leute würden es nicht als "Over Engineering" bezeichnen, sondern als "Best Practice".
S.Lott
9
@ S.lott: Das ist natürlich subjektiv. Ich wollte nur nicht, dass ein Haufen Antworten das Problem abdeckt und sagt, dass Spott gut ist, weil das Verspotten Ihres Codes gutes Design fördert. Im Allgemeinen hasse ich es, mit Code umzugehen, der auf eine Weise entkoppelt ist, die jetzt oder in absehbarer Zukunft keinen offensichtlichen Nutzen bringt. Wenn Sie nicht über mehrere Implementierungen verfügen und diese in absehbarer Zeit nicht erwarten, sollten Sie sie einfach hart programmieren. Es ist einfacher und langweilt den Kunden nicht mit den Details der Abhängigkeiten eines Objekts.
Dsimcha
5
Im Allgemeinen hasse ich es, mit Code umzugehen, der auf eine Weise gekoppelt ist, die keine offensichtlichen Gründe hat, außer einem schlechten Design. Es ist einfacher und langweilt den Kunden nicht mit der Flexibilität, Dinge isoliert zu testen.
S.Lott
3
@S.Lott: Klarstellung: Ich meinte Code, der sich ohne eindeutigen Anwendungsfall erheblich aus dem Weg räumt, um Dinge zu entkoppeln, insbesondere wenn er den Code oder seinen Client-Code erheblich ausführlicher macht, eine weitere Klasse / Schnittstelle usw. einführt Natürlich fordere ich nicht, dass Code enger gekoppelt wird als das einfachste und prägnanteste Design. Auch wenn Sie Linien Abstraktions erstellen vorzeitig sie in der Regel an den falschen Stellen enden.
Dsimcha
Betrachten Sie die Aktualisierung Ihre Frage zu klären , was Unterschied Sie machen. Es ist schwierig, eine Folge von Kommentaren zu integrieren. Bitte aktualisieren Sie die Frage, um sie zu klären und zu fokussieren.
S.Lott

Antworten:

116

Es ist eine Frage der Definition. Ein Test mit Abhängigkeiten ist ein Integrationstest, kein Komponententest. Sie sollten auch eine Integrationstestsuite haben. Der Unterschied besteht darin, dass die Integrationstestsuite möglicherweise in einem anderen Testframework ausgeführt wird und möglicherweise nicht als Teil des Builds, da sie länger dauert.

Für unser Produkt: Unsere Komponententests werden mit jedem Build in Sekunden ausgeführt. Eine Teilmenge unserer Integrationstests wird mit jedem Check-in ausgeführt und dauert 10 Minuten. Unsere vollständige Integrationssuite wird jede Nacht in 4 Stunden ausgeführt.

Jeffrey Faust
quelle
4
Vergessen Sie nicht, Regressionstests durchzuführen, die entdeckte und behobene Fehler abdecken, um deren Wiedereinführung in ein System während der zukünftigen Wartung zu verhindern.
RBerteig
2
Ich würde nicht auf der Definition bestehen, auch wenn ich damit einverstanden bin. Einige Codes können akzeptable Abhängigkeiten aufweisen, z. B. ein StringFormatter, der von den meisten als Komponententest betrachtet wird.
Danidacar
2
danip: klare definitionen sind wichtig und darauf möchte ich bestehen. Es ist aber auch wichtig zu erkennen, dass diese Definitionen ein Ziel sind. Sie sind es wert, angestrebt zu werden, aber Sie brauchen nicht immer ein Bullauge. Unit-Tests sind häufig von Bibliotheken niedrigerer Ebene abhängig.
Jeffrey Faust
2
Es ist auch wichtig, das Konzept der Fassadentests zu verstehen, bei denen nicht geprüft wird, wie Komponenten zusammenpassen (wie Integrationstests), sondern eine einzelne Komponente isoliert getestet wird. (dh ein Objektgraph)
Ricardo Rodrigues
1
Es geht nicht nur darum, schneller zu sein, sondern auch darum, extrem langweilig oder unüberschaubar zu sein. Stellen Sie sich vor, wenn Sie dies nicht tun, wächst Ihr Baum der Verspottung möglicherweise exponentiell. Stellen Sie sich vor, Sie verspotten 10 Abhängigkeiten in Ihrer Einheit, wenn Sie das Verspotten weiter forcieren. Nehmen wir an, 1 von diesen 10 Abhängigkeiten wird an vielen Stellen verwendet und hat 20 eigene Abhängigkeiten. Sie müssen also + 20 andere Abhängigkeiten verspotten, möglicherweise doppelt an vielen Stellen. am finalen api-punkt muss man sich verspotten - zb datenbank, damit man sie nicht zurücksetzen muss und es ist schneller als gesagt
fantomx1
39

Testen mit all den Abhängigkeiten ist immer noch wichtig, aber es geht mehr um Integrationstests, wie Jeffrey Faust sagte.

Einer der wichtigsten Aspekte von Unit-Tests ist es, Ihre Tests vertrauenswürdig zu machen. Wenn Sie nicht glauben, dass ein bestandener Test wirklich bedeutet, dass die Dinge gut sind und dass ein nicht bestandener Test ein Problem im Produktionscode darstellt, sind Ihre Tests bei weitem nicht so nützlich, wie sie sein können.

Um Ihre Tests vertrauenswürdig zu machen, müssen Sie einige Dinge tun, aber ich werde mich für diese Antwort auf eine konzentrieren. Sie müssen sicherstellen, dass sie einfach auszuführen sind, damit alle Entwickler sie problemlos ausführen können, bevor sie den Code einchecken. "Einfach auszuführen" bedeutet, dass Ihre Tests schnell ausgeführt werden und keine umfangreiche Konfiguration oder Einrichtung erforderlich ist, um sie zum Laufen zu bringen. Im Idealfall sollte jeder in der Lage sein, die neueste Version des Codes zu überprüfen, die Tests sofort auszuführen und zu sehen, ob sie bestanden wurden.

Durch das Abstrahieren von Abhängigkeiten von anderen Dingen (Dateisystem, Datenbank, Webservices usw.) können Sie die erforderliche Konfiguration vermeiden und sind weniger anfällig für Situationen, in denen Sie versucht sind, "Oh, Tests sind fehlgeschlagen, weil ich nicht" zu sagen. Ich habe die Netzwerkfreigabe nicht eingerichtet. Na ja. Ich werde sie später ausführen. "

Wenn Sie testen möchten, was Sie mit einigen Daten tun, sollten sich Ihre Unit-Tests für diesen Geschäftslogikcode nicht darum kümmern, wie Sie diese Daten erhalten. Es ist fantastisch, die Kernlogik Ihrer Anwendung testen zu können, ohne auf die Unterstützung von Dingen wie Datenbanken angewiesen zu sein. Wenn Sie es nicht tun, verpassen Sie es.

PS Ich sollte hinzufügen, dass es definitiv möglich ist, im Namen der Testbarkeit zu überdenken. Das Testen Ihrer Anwendung trägt dazu bei, dies zu vermeiden. In jedem Fall machen schlechte Implementierungen eines Ansatzes den Ansatz jedoch nicht weniger gültig. Alles kann missbraucht und übertrieben werden, wenn man nicht immer fragt: "Warum mache ich das?" während der Entwicklung.


In Bezug auf interne Abhängigkeiten wird es etwas matschig. Ich denke gerne darüber nach, dass ich meine Klasse so gut wie möglich davor schützen möchte, sich aus den falschen Gründen zu ändern. Wenn ich ein Setup wie dieses habe ...

public class MyClass 
{
    private SomeClass someClass;
    public MyClass()
    {
        someClass = new SomeClass();
    }

    // use someClass in some way
}

Es ist mir im Allgemeinen egal, wie SomeClasserstellt wird. Ich möchte es nur benutzen. Wenn SomeClass sich ändert und nun Parameter für den Konstruktor benötigt, ist das nicht mein Problem. Ich sollte MyClass nicht ändern müssen, um das zu berücksichtigen.

Nun, das berührt nur den Designteil. Bei Unit-Tests möchte ich mich auch vor anderen Klassen schützen. Wenn ich MyClass teste, mag ich es zu wissen, dass es keine externen Abhängigkeiten gibt, dass SomeClass zu irgendeinem Zeitpunkt keine Datenbankverbindung oder keinen anderen externen Link eingeführt hat.

Ein noch größeres Problem ist, dass ich auch weiß, dass einige Ergebnisse meiner Methoden von der Ausgabe einer Methode in SomeClass abhängen. Ohne SomeClass zu verspotten / auszublenden, habe ich möglicherweise keine Möglichkeit, diesen Input in der Nachfrage zu variieren. Wenn ich Glück habe, kann ich meine Umgebung im Test möglicherweise so zusammenstellen, dass die richtige Antwort von SomeClass ausgelöst wird. Auf diese Weise werden meine Tests jedoch komplexer und spröder.

Wenn ich MyClass so umschreibe, dass eine Instanz von SomeClass im Konstruktor akzeptiert wird, kann ich eine gefälschte Instanz von SomeClass erstellen, die den gewünschten Wert zurückgibt (entweder über ein spöttisches Framework oder mit einem manuellen Mock). In diesem Fall muss ich in der Regel keine Schnittstelle einführen. Ob Sie dies tun oder nicht, ist in vielerlei Hinsicht eine persönliche Entscheidung, die von der Sprache Ihrer Wahl bestimmt wird (z. B. sind Benutzeroberflächen in C # wahrscheinlicher, aber in Ruby benötigen Sie definitiv keine).

Adam Lear
quelle
+1 Tolle Antwort, da externe Abhängigkeiten ein Fall sind, an den ich beim Verfassen der ursprünglichen Frage nicht gedacht habe. Ich habe meine Frage als Antwort geklärt. Siehe die neueste Bearbeitung.
Dsimcha
@dsimcha Ich habe meine Antwort erweitert, um darauf näher einzugehen. Ich hoffe es hilft.
Adam Lear
Adam, können Sie eine Sprache vorschlagen, in der "Wenn SomeClass sich ändert und jetzt Parameter für den Konstruktor benötigt ... Ich sollte MyClass nicht ändern müssen" wahr ist? Tut mir leid, das ist mir als ungewöhnliche Anforderung aufgefallen. Ich kann sehen, dass ich die Komponententests für MyClass nicht ändern muss, aber MyClass nicht ändern muss ... wow.
1
@moz Was ich damit meinte war, dass sich MyClass nicht ändern muss, wenn SomeClass in SomeClass eingefügt wird, anstatt intern erstellt zu werden. Unter normalen Umständen sollte sich MyClass nicht um Setup-Details für SomeClass kümmern müssen. Wenn sich die Oberfläche von SomeClass ändert, muss MyClass noch geändert werden, wenn eine der verwendeten Methoden betroffen ist.
Adam Lear
1
Wenn Sie SomeClass beim Testen von MyClass verspotten, wie können Sie feststellen, ob SomeClass von MyClass falsch verwendet wird oder sich auf eine nicht getestete Eigenheit von SomeClass stützt, die sich möglicherweise ändert?
Namey
22

Berücksichtigen Sie neben dem Thema Unit vs. Integrationstest Folgendes.

Das Klassen-Widget ist abhängig von den Klassen Thingamajig und WhatsIt.

Ein Komponententest für Widget schlägt fehl.

In welcher Klasse liegt das Problem?

Wenn Sie mit "Starten Sie den Debugger" geantwortet haben oder "Lesen Sie den Code durch, bis ich ihn finde", verstehen Sie, wie wichtig es ist, nur die Einheit und nicht die Abhängigkeiten zu testen.

Bach
quelle
3
@Brook: Wie wäre es, wenn Sie die Ergebnisse für alle Abhängigkeiten des Widgets sehen würden? Wenn sie alle bestehen, liegt ein Problem mit Widget vor, bis das Gegenteil bewiesen ist.
Dsimcha
4
@dsimcha, aber jetzt fügst du dem Spiel wieder Komplexität hinzu, um die Zwischenschritte zu überprüfen. Warum nicht einfach vereinfachen und zuerst einfache Unit-Tests durchführen? Dann machen Sie Ihren Integrationstest.
Asoundmove
1
@dsimcha, das hört sich vernünftig an, bis Sie in ein nicht triviales Abhängigkeitsdiagramm geraten. Angenommen, Sie haben ein komplexes Objekt mit mehr als drei Ebenen und Abhängigkeiten. Es wird zu einer O (N ^ 2) -Suche nach dem Problem und nicht zu O (1)
Brook,
1
Meine Interpretation des SRP ist auch, dass eine Klasse eine einzige Verantwortung auf der Ebene des Begriffs / der Problemdomäne haben sollte. Es spielt keine Rolle, ob die Erfüllung dieser Verantwortung viele verschiedene Dinge erfordert, wenn sie auf einer niedrigeren Abstraktionsebene betrachtet wird. Im Extremfall würde die SRP OO widersprechen, da die meisten Klassen Daten enthalten und Operationen daran ausführen (zwei Dinge, wenn sie auf einer ausreichend niedrigen Ebene betrachtet werden).
Dsimcha
4
@Brook: Mehr Typen erhöhen nicht die Komplexität an sich. Weitere Typen sind in Ordnung, wenn diese Typen in der Problemdomäne konzeptionell sinnvoll sind und das Verständnis des Codes erleichtern und nicht erschweren. Das Problem ist das künstliche Entkoppeln von Dingen, die konzeptionell auf der Problemdomänenebene gekoppelt sind (dh Sie haben nur eine Implementierung, werden wahrscheinlich nie mehr als eine haben usw.), und das Entkoppeln lässt sich nicht gut auf Problemdomänenkonzepte abbilden. In diesen Fällen ist es albern, bürokratisch und wortreich, um diese Implementierung ernsthafte Abstraktionen zu erstellen.
dsimcha
14

Stellen Sie sich vor, Programmieren ist wie Kochen. Dann ist Unit Testing dasselbe, als ob Sie sicherstellen, dass Ihre Zutaten frisch, lecker usw. sind. Beim Integrationstest wird sichergestellt, dass Ihre Mahlzeit köstlich ist.

Letztendlich ist es das Wichtigste, sicherzustellen, dass Ihre Mahlzeit köstlich ist (oder dass Ihr System funktioniert), das ultimative Ziel. Aber wenn Ihre Zutaten, ich meine, Einheiten, funktionieren, haben Sie eine billigere Möglichkeit, dies herauszufinden.

In der Tat ist es wahrscheinlicher, dass Sie ein funktionierendes System haben, wenn Sie sicherstellen können, dass Ihre Einheiten / Methoden funktionieren. Ich betone eher "wahrscheinlich" als "sicher". Sie brauchen immer noch Ihre Integrationstests, genauso wie Sie immer noch jemanden brauchen, der das gekochte Essen probiert und Ihnen mitteilt, dass das Endprodukt gut ist. Sie werden es leichter haben, mit frischen Zutaten dorthin zu gelangen, das ist alles.

Julio
quelle
7
Und wenn Ihre Integrationstests fehlschlagen, kann der Komponententest das Problem beheben.
Tim Williscroft
9
Um eine Analogie zu formulieren: Wenn Sie feststellen, dass Ihr Essen schrecklich schmeckt, müssen Sie möglicherweise einige Untersuchungen durchführen, um festzustellen, ob Ihr Brot schimmelig ist. Das Ergebnis ist jedoch, dass Sie einen Einheitentest hinzufügen, um vor dem Kochen auf schimmliges Brot zu prüfen, sodass dieses bestimmte Problem nicht erneut auftreten kann. Wenn Sie später noch einmal eine Mahlzeit versagen, haben Sie schimmeliges Brot als Ursache beseitigt.
Kyralessa
Liebe diese Analogie!
Thehowler
6

Wenn Sie die Einheiten vollständig isolieren, können Sie ALLE möglichen Variationen von Daten und Situationen testen, die von dieser Einheit übermittelt werden können. Da es vom Rest isoliert ist, können Sie Abweichungen ignorieren, die sich nicht direkt auf das zu testende Gerät auswirken. Dies wiederum verringert die Komplexität der Tests erheblich.

Durch das Testen mit verschiedenen integrierten Abhängigkeitsebenen können Sie bestimmte Szenarien testen, die in den Komponententests möglicherweise nicht getestet wurden.

Beides ist wichtig. Wenn Sie nur einen Komponententest durchführen, treten bei der Integration von Komponenten immer komplexere, subtile Fehler auf. Wenn Sie nur Integrationstests durchführen, testen Sie ein System, ohne die Gewissheit zu haben, dass die einzelnen Maschinenteile nicht getestet wurden. Zu glauben, dass Sie einen besseren vollständigen Test nur durch Integrationstests erzielen können, ist nahezu unmöglich, da die Anzahl der Einträge mit der Anzahl der hinzugefügten Komponenten SEHR schnell zunimmt (faktoriell denken) und die Erstellung eines Tests mit ausreichender Abdeckung sehr schnell unmöglich wird.

Kurz gesagt, die drei Ebenen des "Komponententests", die ich normalerweise in fast allen meinen Projekten verwende:

  • Unit-Tests, isoliert mit verspotteten oder gestoppelten Abhängigkeiten, um die Hölle einer einzelnen Komponente zu testen. Idealerweise würde man eine vollständige Abdeckung versuchen.
  • Integrationstests zum Testen der subtileren Fehler. Sorgfältig gestaltete Stichproben, die Grenzfälle und typische Bedingungen aufzeigen. Eine vollständige Abdeckung ist häufig nicht möglich. Der Aufwand konzentriert sich darauf, was zum Ausfall des Systems führen würde.
  • Spezifikationstests zum Einspeisen verschiedener realer Daten in das System, Instrumentieren der Daten (falls möglich) und Beobachten der Ausgabe, um sicherzustellen, dass sie den Spezifikationen und Geschäftsregeln entsprechen.

Die Abhängigkeitsinjektion ist ein sehr effizientes Mittel, um dies zu erreichen, da es ermöglicht, Komponenten für Komponententests sehr einfach zu isolieren, ohne das System komplexer zu machen. Ihr Geschäftsszenario rechtfertigt möglicherweise nicht die Verwendung eines Injektionsmechanismus, Ihr Testszenario wird dies jedoch beinahe tun. Das reicht für mich aus, um dann unverzichtbar zu machen. Sie können sie auch verwenden, um die verschiedenen Abstraktionsebenen unabhängig voneinander durch Teilintegrationstests zu testen.

Newtopian
quelle
4

Was ist die andere Seite davon? Ist es wirklich wichtig, dass ein Unit-Test nicht auch seine Abhängigkeiten testet? Wenn ja warum?

Einheit. Bedeutet Singular.

Das Testen von 2 Dingen bedeutet, dass Sie die beiden Dinge und alle funktionalen Abhängigkeiten haben.

Wenn Sie eine dritte Sache hinzufügen, erhöhen Sie die funktionalen Abhängigkeiten in den Tests darüber hinaus linear. Zusammenhänge zwischen Dingen wachsen schneller als die Anzahl der Dinge.

Es gibt n (n-1) / 2 mögliche Abhängigkeiten unter n getesteten Gegenständen.

Das ist der große Grund.

Einfachheit hat Wert.

S.Lott
quelle
2

Erinnerst du dich, wie du zuerst gelernt hast, Rekursion zu machen? Mein Professor sagte "Angenommen, Sie haben eine Methode, die x tut" (zB löst Fibbonacci für jedes x). Msgstr "Um nach x aufzulösen, müssen Sie diese Methode für x - 1 und x - 2 aufrufen". In gleicher Weise können Sie durch Ausblenden von Abhängigkeiten so tun, als ob sie existieren, und testen, ob die aktuelle Einheit das tut, was sie tun soll. Die Annahme ist natürlich, dass Sie die Abhängigkeiten so rigoros testen.

Dies ist im Wesentlichen die SRP bei der Arbeit. Die Konzentration auf eine einzige Verantwortung, auch für Ihre Tests, beseitigt die Menge an mentalem Jonglieren, die Sie tun müssen.

Michael Brown
quelle
2

(Dies ist eine kleine Antwort. Danke @TimWilliscroft für den Hinweis.)

Fehler sind leichter zu lokalisieren, wenn:

  • Sowohl das zu testende Gerät als auch jede seiner Abhängigkeiten werden unabhängig getestet.
  • Jeder Test schlägt nur dann fehl, wenn der vom Test abgedeckte Code fehlerhaft ist.

Das funktioniert gut auf Papier. Wie in der Beschreibung des OP dargestellt (Abhängigkeiten sind fehlerhaft), ist es jedoch schwierig, den Ort des Fehlers zu bestimmen, wenn die Abhängigkeiten nicht getestet werden.

rwong
quelle
Warum werden die Abhängigkeiten nicht getestet? Sie sind vermutlich niedriger und einfacher zu testen. Darüber hinaus ist es bei Komponententests, die einen bestimmten Code abdecken, einfacher, den Ort des Fehlers zu lokalisieren.
David Thornley
2

Viele gute Antworten. Ich möchte noch ein paar weitere Punkte hinzufügen:

Mit Unit-Tests können Sie Ihren Code auch testen, wenn keine Abhängigkeiten vorhanden sind . ZB Sie oder Ihr Team haben die anderen Ebenen noch nicht geschrieben, oder Sie warten auf eine Schnittstelle, die von einem anderen Unternehmen bereitgestellt wurde.

Unit-Tests bedeuten auch, dass Sie keine vollständige Umgebung auf Ihrem Entwicklungscomputer haben müssen (z. B. eine Datenbank, einen Webserver usw.). Ich würde allen Entwicklern dringend empfehlen, eine solche Umgebung zu haben, wie klein sie auch sein mag , um Bugs usw. zu reproduzieren. Wenn es jedoch aus irgendeinem Grund nicht möglich ist, die Produktionsumgebung nachzuahmen, erhalten Sie durch Unit-Tests zumindest ein gewisses Niveau Vertrauen in Ihren Code, bevor er in ein größeres Testsystem eingeht.

Steve
quelle
0

Zu den Designaspekten: Ich glaube, dass auch kleine Projekte davon profitieren, den Code testbar zu machen. Sie müssen nicht unbedingt so etwas wie Guice einführen (eine einfache Factory-Klasse wird es oft tun), aber die Trennung des Konstruktionsprozesses von der Programmierlogik führt zu

  • Die Abhängigkeiten jeder Klasse über die Benutzeroberfläche klar dokumentieren (sehr hilfreich für Leute, die neu im Team sind)
  • Die Klassen werden viel klarer und einfacher zu pflegen (sobald Sie die hässliche Objektgraphenerstellung in eine separate Klasse eingeordnet haben).
  • lose Kupplung (erleichtert Änderungen)
Oliver Weiler
quelle
2
Methode: Ja, aber Sie müssen zusätzlichen Code und zusätzliche Klassen hinzufügen, um dies zu tun. Der Code sollte so kurz wie möglich sein und dennoch lesbar sein. IMHO das Hinzufügen von Fabriken und so weiter ist Überentwicklung, es sei denn, Sie können nachweisen, dass Sie die Flexibilität benötigen, die sie bietet, oder es ist sehr wahrscheinlich, dass Sie diese benötigen.
Dsimcha
0

Äh ... es gibt gute Punkte zum Unit- und Integrationstest, die in diesen Antworten hier geschrieben sind!

Ich vermisse die kostenbezogenen und praktischen Ansichten hier. Das heißt, ich sehe klar den Vorteil von sehr isolierten / atomaren Einheitentests (möglicherweise sehr unabhängig voneinander und mit der Option, sie parallel und ohne Abhängigkeiten wie Datenbanken, Dateisystem usw. auszuführen) und Integrationstests (höherer Ebene). es geht aber auch um kosten (zeit, geld, ...) und risiken .

Es gibt also andere Faktoren, die viel wichtiger sind (wie "Was soll getestet werden?" ), Bevor Sie aus meiner Erfahrung heraus über "Wie soll getestet werden ?" Nachdenken ...

Zahlt mein Kunde (implizit) für den zusätzlichen Aufwand für das Schreiben und die Wartung von Tests? Ist ein eher testbasierter Ansatz (schreiben Sie zuerst die Tests, bevor Sie den Code schreiben) in meiner Umgebung wirklich kosteneffizient (Analyse von Codefehlerrisiken / -kosten, Personen, Designspezifikationen, Einrichten der Testumgebung)? Code ist immer fehlerhaft, aber könnte es kostengünstiger sein, das Testen auf die Produktionsnutzung zu verlagern (im schlimmsten Fall!)?

Es hängt auch stark davon ab, wie Ihre Codequalität (Standards) ist oder welche Frameworks, IDEs, Designprinzipien usw. Sie und Ihr Team befolgen und wie erfahren sie sind. Ein gut geschriebener, leicht verständlicher, gut genug dokumentierter (idealerweise selbstdokumentierender), modularer, ... Code führt wahrscheinlich weniger Fehler ein als das Gegenteil. Der tatsächliche "Bedarf", Druck oder die Gesamtkosten für Wartung / Bugfixes / Risiken für umfangreiche Tests sind daher möglicherweise nicht hoch.

Lassen Sie es uns auf die Spitze treiben, als ein Mitarbeiter in meinem Team vorschlug, dass wir versuchen müssen, unseren reinen Java EE-Modellschichtcode mit einer gewünschten 100% -igen Abdeckung für alle Klassen in der Datenbank zu testen und die Datenbank zu verspotten. Oder der Manager, der möchte, dass die Integrationstests mit 100% aller möglichen realen Anwendungsfälle und Web-UI-Workflows abgedeckt werden, weil wir nicht riskieren möchten, dass ein Anwendungsfall fehlschlägt. Aber wir haben ein knappes Budget von ungefähr 1 Million Euro, einen ziemlich engen Plan, um alles zu programmieren. Eine Kundenumgebung, in der potenzielle Anwendungsfehler keine große Gefahr für Menschen oder Unternehmen darstellen. Unsere App wird intern mit (einigen) wichtigen Komponententests, Integrationstests, wichtigen Kundentests mit festgelegten Testplänen, einer Testphase usw. getestet. Wir entwickeln keine App für eine Kernfabrik oder die pharmazeutische Produktion!

Ich selbst versuche, wenn möglich einen Test zu schreiben und entwickle ihn, während ich meinen Code teste. Aber ich mache es oft von oben nach unten (Integrationstests) und versuche, den richtigen Punkt zu finden, an dem die "App-Ebene" für die wichtigen Tests zugeschnitten wird (oft in der Modellebene). (weil es oft um die "schichten" geht)

Darüber hinaus bleibt der Code für den Unit- und Integrationstest nicht ohne negative Auswirkungen auf Zeit, Geld, Wartung, Codierung usw.. Er ist cool und sollte angewendet werden, jedoch mit Vorsicht und unter Berücksichtigung der Auswirkungen beim Start oder nach 5 Jahren vieler entwickelter Tests Code.

Ich würde also sagen, es kommt sehr auf Vertrauen und Kosten / Risiko / Nutzen-Bewertung an ... wie im echten Leben, wo man nicht mit viel oder 100% Sicherheitsmechanismen herumlaufen kann und will.

Das Kind kann und sollte irgendwo hochklettern und kann hinfallen und sich verletzen. Das Auto funktioniert möglicherweise nicht mehr, weil ich den falschen Kraftstoff eingefüllt habe (ungültige Eingabe :)). Der Toast kann verbrannt werden, wenn der Zeitknopf nach 3 Jahren nicht mehr funktioniert. Aber ich möchte niemals auf der Autobahn fahren und mein abgenommenes Lenkrad in meinen Händen halten :)

Andreas Dietrich
quelle