355 Stimmen

Was ist der Unterschied zwischen Integrations- und Einheitstests?

Ich kenne die sogenannte Lehrbuchdefinition von Unit-Tests und Integrationstests. Was mich interessiert, ist, wann es Zeit ist, Unit-Tests zu schreiben... Ich werde sie so schreiben, dass sie so viele Klassen wie möglich abdecken.

Zum Beispiel, wenn ich eine Word Klasse, werde ich einige Unit-Tests für die Word Klasse. Dann beginne ich mit dem Schreiben meiner Sentence Klasse, und wenn sie mit der Word Klasse, werde ich meine Unit-Tests oft so schreiben, dass sie sowohl die Sentence y Word ... zumindest an den Orten, an denen sie interagieren.

Sind diese Tests im Wesentlichen Integrationstests geworden, weil sie jetzt die Integration dieser 2 Klassen testen, oder ist es nur ein Unit-Test, der 2 Klassen überspannt?

Im Allgemeinen werde ich aufgrund dieser unsicheren Linie nur selten Integrationstests schreiben... oder ist die Verwendung des fertigen Produkts, um zu sehen, ob alle Teile richtig funktionieren, der eigentliche Integrationstest, auch wenn er manuell durchgeführt wird und selten über den Umfang der einzelnen Funktionen hinausgeht?

Verstehe ich Integrationstests falsch, oder gibt es wirklich nur sehr wenig Unterschied zwischen Integrations- und Unit-Tests?

344voto

Arialdo Martini Punkte 4307

Der entscheidende Unterschied ist für mich, dass Integrationstests zeigen, ob eine Funktion funktioniert oder defekt ist, da sie den Code in einem realitätsnahen Szenario testen. Sie rufen eine oder mehrere Software-Methoden oder -Funktionen auf und testen, ob sie sich wie erwartet verhalten.

Auf der anderen Seite ist ein Einheitstest Das Testen einer einzelnen Methode beruht auf der (oft falschen) Annahme, dass der Rest der Software korrekt funktioniert, da es explizit jede Abhängigkeit abbildet.

Wenn also ein Einheitstest für eine Methode, die ein bestimmtes Merkmal implementiert, grün ist, bedeutet dies no bedeutet, dass die Funktion funktioniert.

Angenommen, Sie haben eine Methode wie diese:

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  Log.TrackTheFactYouDidYourJob();
  return someResults;
}

DoSomething ist für Ihren Kunden sehr wichtig: Es ist ein Merkmal, das Einzige, was zählt. Deshalb schreiben Sie normalerweise eine Cucumber-Spezifikation, die dies bestätigt: Sie möchten Überprüfen Sie y kommunizieren die Funktion funktioniert oder nicht.

Feature: To be able to do something
  In order to do something
  As someone
  I want the system to do this thing

Scenario: A sample one
  Given this situation
  When I do something
  Then what I get is what I was expecting for

Kein Zweifel: Wenn der Test erfolgreich ist, können Sie behaupten, dass Sie eine funktionierende Funktion liefern. Das kann man so nennen Geschäftswert .

Wenn Sie einen Unit-Test schreiben wollen für DoSomething sollten Sie (unter Verwendung einiger Mocks) vorgeben, dass der Rest der Klassen und Methoden funktioniert (d.h., dass alle Abhängigkeiten, die die Methode verwendet, korrekt funktionieren) und behaupten, dass Ihre Methode funktioniert.

In der Praxis machen Sie so etwas wie:

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log
  return someResults;
}

Sie können dies mit Dependency Injection, einer Factory-Methode oder einem Mock-Framework tun oder einfach die zu testende Klasse erweitern.

Angenommen, es gibt einen Fehler in Log.DoSomething() . Glücklicherweise findet die Gherkin-Spezifikation dies, und Ihre End-to-End-Tests werden fehlschlagen.

Die Funktion wird nicht funktionieren, weil Log kaputt ist, nicht weil [Do your job with someInput] seine Aufgabe nicht erfüllt. Und, nebenbei bemerkt, [Do your job with someInput] ist die alleinige Verantwortung für diese Methode.

Nehmen wir außerdem an Log wird in 100 anderen Funktionen, in 100 anderen Methoden von 100 anderen Klassen verwendet.

Ja, 100 Funktionen werden ausfallen. Aber glücklicherweise schlagen auch 100 End-to-End-Tests fehl und decken das Problem auf. Und, ja: sie sagen die Wahrheit .

Das sind sehr nützliche Informationen: Ich weiß, dass ich ein defektes Produkt habe. Es ist auch eine sehr verwirrende Information: Sie sagt mir nichts darüber, wo das Problem liegt. Sie teilt mir das Symptom mit, nicht die eigentliche Ursache.

Dennoch, DoSomething ist grün, weil er eine gefälschte Log gebaut, um nie zu brechen. Und, ja: Es ist eindeutig eine Lüge. . Es wird mitgeteilt, dass eine defekte Funktion funktioniert. Wie kann das nützlich sein?

(Wenn DoSomething() Unit-Test fehlschlägt, seien Sie sicher: [Do your job with someInput] hat einige Bugs).

Nehmen wir an, es handelt sich um ein System mit einer defekten Klasse: A system with a broken class

Ein einziger Fehler macht mehrere Funktionen kaputt, und mehrere Integrationstests werden fehlschlagen.

A single bug will break several features, and several integration tests will fail

Andererseits kann derselbe Fehler auch nur einen einzigen Unit-Test zerstören.

The same bug will break just one unit test

Vergleichen Sie nun die beiden Szenarien.

Derselbe Fehler wird nur einen einzigen Unit-Test zerstören.

  • Alle Ihre Funktionen unter Verwendung der gebrochenen Log rot sind
  • Alle Ihre Unit-Tests sind grün, nur der Unit-Test für Log ist rot

Eigentlich sind die Unit-Tests für alle Module, die ein defektes Feature verwenden, grün, weil sie durch die Verwendung von Mocks Abhängigkeiten entfernt haben. Mit anderen Worten: Sie laufen in einer idealen, völlig fiktiven Welt. Und das ist die einzige Möglichkeit, Fehler zu isolieren und sie zu finden. Unit-Testing bedeutet Mocking. Wer kein Mocking betreibt, betreibt auch kein Unit Testing.

Der Unterschied

Integrationstests zeigen was funktioniert nicht. Aber sie sind nicht von Nutzen in raten, wo könnte das Problem sein.

Einheitstests sind die einzigen Tests, die Ihnen sagen wobei genau der Fehler ist. Um diese Informationen zu erhalten, müssen sie die Methode in einer simulierten Umgebung ausführen, in der alle anderen Abhängigkeiten korrekt funktionieren sollen.

Deshalb denke ich, dass Ihr Satz "Oder ist es nur ein Einheitstest, der sich über 2 Klassen erstreckt" irgendwie deplatziert ist. Ein Unit-Test sollte sich niemals über 2 Klassen erstrecken.

Diese Antwort ist im Grunde eine Zusammenfassung dessen, was ich hier geschrieben habe: Unit-Tests lügen, deshalb liebe ich sie .

65voto

Larry Foulkrod Punkte 2244

Wenn ich Unit-Tests schreibe, beschränke ich den Umfang des getesteten Codes auf die Klasse, die ich gerade schreibe, indem ich Abhängigkeiten einbeziehe. Wenn ich eine Klasse Sentence schreibe und Sentence von Word abhängig ist, verwende ich ein Mock Word. Durch das Mocking von Word kann ich mich nur auf dessen Schnittstelle konzentrieren und die verschiedenen Verhaltensweisen meiner Sentence-Klasse testen, während sie mit der Schnittstelle von Word interagiert. Auf diese Weise teste ich nur das Verhalten und die Implementierung von Sentence und nicht gleichzeitig auch die Implementierung von Word.

Nachdem ich die Unit-Tests geschrieben habe, um sicherzustellen, dass sich Sentence bei der Interaktion mit Word auf der Grundlage der Word-Schnittstelle korrekt verhält, schreibe ich den Integrationstest, um sicherzustellen, dass meine Annahmen über die Interaktionen korrekt waren. Dazu stelle ich die eigentlichen Objekte zur Verfügung und schreibe einen Test, der eine Funktion übt, die am Ende sowohl Sentence als auch Word verwenden wird.

53voto

Michu93 Punkte 3978

Beim Unit-Test testen Sie jeden Teil isoliert: enter image description here

Beim Integrationstest testen Sie viele Module Ihres Systems:

enter image description here

und das passiert, wenn man nur Unit-Tests verwendet (im Allgemeinen funktionieren beide Windows, leider nicht zusammen):

enter image description here

Fuentes: Quelle1 Quelle2

47voto

Rob Cooper Punkte 28132

Meine 10 Bits :D

Mir wurde immer gesagt, dass Einheitliche Tests ist die Prüfung eines Einzelteil - die in vollem Umfang ausgeübt werden sollte. Da die meisten Komponenten aus kleineren Teilen bestehen, hat dies viele Ebenen. Für mich ist eine Einheit ist ein funktioneller Teil des Systems. Es muss also etwas Wertvolles bereitstellen (d.h. keine Methode zum Parsen von Strings, sondern eine HtmlSanitizer vielleicht).

Integrationstests ist der nächste Schritt nach oben, es geht darum, eine oder mehrere Komponenten zu nehmen und sicherzustellen, dass sie so zusammenarbeiten, wie sie sollten. Sie sind dann über die Feinheiten der Sorge über wie die Komponenten funktionieren einzeln, aber wenn Sie html in Ihr System eingeben HtmlEditControl weiß es irgendwie auf magische Weise, ob es gültig ist oder nicht.

Es ist allerdings eine sehr bewegliche Linie. Ich würde mich lieber darauf konzentrieren, den verdammten Code zum Laufen zu bringen, Punkt ^_^

23voto

Robert Koritnik Punkte 100480

Unit-Tests verwenden Mocks

Das, was Sie meinen, sind Integrationstests, die die gesamte Integration Ihres Systems testen. Aber wenn Sie Unit-Tests durchführen, sollten Sie eigentlich jede Unit einzeln testen. Alles andere sollte gemockt werden. Also in Ihrem Fall von Sentence Klasse, wenn sie die Word Klasse, dann wird Ihr Word Klasse verspottet werden sollte. Auf diese Weise testen Sie nur Ihre Sentence Klassenfunktionalität.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X