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 .