Automatisierte Unit-Tests, Integrationstests oder Abnahmetests [geschlossen]

29

TDD- und Unit-Tests scheinen im Moment der große Rave zu sein. Aber ist es wirklich so nützlich im Vergleich zu anderen Formen des automatisierten Testens?

Intuitiv würde ich vermuten, dass automatisierte Integrationstests viel nützlicher sind als Komponententests. Nach meiner Erfahrung liegen die meisten Fehler in der Interaktion zwischen Modulen und nicht so sehr in der tatsächlichen (normalerweise eingeschränkten) Logik der einzelnen Einheiten. Auch Regressionen traten häufig auf, weil sich die Schnittstellen zwischen Modulen (und die Vor- und Nachbedingungen) änderten.

Verstehe ich etwas falsch oder warum werden Unit-Tests im Vergleich zu Integrationstests so stark in den Fokus gerückt? Es ist einfach so, weil davon ausgegangen wird, dass Sie Integrationstests durchführen und Unit-Tests das nächste sind, was wir lernen müssen, um uns als Entwickler zu bewerben.

Oder liefert Unit Testing einfach den höchsten Gewinn im Vergleich zur Komplexität der Automatisierung?

Welche Erfahrungen haben Sie mit automatisierten Komponententests, automatisierten Integrationstests und automatisierten Abnahmetests gemacht und welche haben nach Ihrer Erfahrung den höchsten ROI erzielt? und warum?

Wenn Sie nur eine Testform auswählen müssten, um bei Ihrem nächsten Projekt automatisiert zu werden, welche wäre das?

Danke im Voraus.

Bjarke Freund-Hansen
quelle
Ich möchte nur einen verspäteten Link zu JB Rainsbergers Integrationstests Are A Scam hinzufügen . Es zeigt viele der Gründe auf, warum Integrationstests eine falsche Wirtschaftlichkeit sind.
Tim
6
Dies ist ein weiteres Beispiel für das Schließen einer Frage, die vor drei Jahren auf dieser Website gestellt wurde. Es ist wirklich ärgerlich, zu einer Community beizutragen, in der sich die Regeln ändern und Sie einfach alles Alte wegwerfen!
Bjarke Freund-Hansen

Antworten:

34

Ein wichtiger Faktor, der Unit-Tests äußerst nützlich macht, ist die schnelle Rückmeldung .

Überlegen Sie, was passiert, wenn Ihre App vollständig mit Integrations- / System- / Funktionstests abgedeckt ist (dies ist bereits eine ideale Situation, die in den meisten Entwicklungsgeschäften weit von der Realität entfernt ist). Diese werden oft von einem engagierten Testteam durchgeführt.

  • Sie schreiben eine Änderung am SCM-Repo fest,
  • Irgendwann (möglicherweise Tage) später erhalten die Test-Leute eine neue interne Version und beginnen, diese zu testen.
  • sie finden einen Fehler und reichen einen Fehlerbericht ein,
  • (im Idealfall) jemand weist Ihnen den Fehlerbericht zurück.

Dies kann Tage oder sogar Wochen dauern. Zu diesem Zeitpunkt haben Sie bereits an anderen Aufgaben gearbeitet, sodass Sie nicht die winzigen Details des zuvor geschriebenen Codes im Kopf haben. Darüber hinaus haben Sie in der Regel nicht einmal einen direkten Beweis dafür, wo sich der Fehler tatsächlich befindet. Daher dauert es sehr lange, den Fehler zu finden und zu beheben.

Während in Unit-Tests (TDD)

  • Sie schreiben einen Test,
  • Sie schreiben einen Code, um den Test zu erfüllen,
  • der Test schlägt immer noch fehl,
  • Sie sehen sich den Code an und haben in der Regel in wenigen Sekunden ein "Hoppla" -Erlebnis (wie "Hoppla, ich habe vergessen, nach dieser Bedingung zu suchen!")
  • Beheben Sie den Fehler sofort.

Dies alles geschieht in wenigen Minuten .

Dies soll nicht heißen, dass Integrations- / Systemtests nicht nützlich sind. Sie dienen nur unterschiedlichen Zwecken. Mit gut geschriebenen Unit-Tests können Sie einen großen Teil der Fehler im Code abfangen, bevor sie in die Integrationsphase gelangen, in der es bereits erheblich teurer ist, sie zu finden und zu beheben. Sie haben Recht, dass die Integrationstests erforderlich sind, um die Arten von Fehlern zu erkennen, die mit Komponententests nur schwer oder gar nicht zu erkennen sind. Nach meiner Erfahrung sind dies jedoch die selteneren; Die meisten der Fehler, die ich gesehen habe, sind auf ein einfaches oder sogar triviales Auslassen innerhalb einer Methode zurückzuführen.

Ganz zu schweigen davon, dass durch Unit-Tests auch Ihre Schnittstellen auf Benutzerfreundlichkeit / Sicherheit usw. getestet werden. Auf diese Weise erhalten Sie ein äußerst wichtiges Feedback zur Verbesserung Ihres Designs und Ihrer APIs. Welche IMHO kann die Wahrscheinlichkeit von Modul- / Susbsystem-Integrationsfehlern erheblich verringern: Je einfacher und sauberer eine API ist, desto geringer ist die Wahrscheinlichkeit von Missverständnissen oder Auslassungen.

Welche Erfahrungen haben Sie mit automatisierten Komponententests, automatisierten Integrationstests und automatisierten Abnahmetests gemacht und welche haben nach Ihrer Erfahrung den höchsten ROI erzielt? und warum?

Der ROI hängt von vielen Faktoren ab. Wahrscheinlich hängt der wichtigste davon ab, ob es sich bei Ihrem Projekt um ein neues oder ein älteres Projekt handelt. Bei der Entwicklung auf der grünen Wiese ist mein Rat (und meine bisherige Erfahrung), von Anfang an einen TDD-Test durchzuführen. Ich bin zuversichtlich, dass dies in diesem Fall die kostengünstigste Methode ist.

In einem Legacy-Projekt ist der Aufbau einer ausreichenden Abdeckung durch Komponententests jedoch ein großes Unterfangen, das sich nur sehr langsam auszahlt. Es ist effizienter, zu versuchen, die wichtigsten Funktionen mit System- / Funktionstests über die Benutzeroberfläche abzudecken, wenn dies möglich ist. (Es kann schwierig sein, Desktop-GUI-Apps automatisch über die GUI zu testen, obwohl sich die Tools zur Unterstützung automatisierter Tests allmählich verbessern ...). Dadurch erhalten Sie schnell ein grobes, aber wirksames Sicherheitsnetz. Anschließend können Sie nach und nach Komponententests für die wichtigsten Teile der App erstellen.

Wenn Sie bei Ihrem nächsten Projekt nur eine Testform für die Automatisierung auswählen müssten, welche wäre das?

Das ist eine theoretische Frage und ich finde sie sinnlos. Alle Arten von Tests können in der Toolbox eines guten SW-Ingenieurs verwendet werden, und all diese Szenarien sind unersetzbar.

Péter Török
quelle
2
+1 für "schnelle Rückmeldung" bei Unit-Tests. Sehr praktisch für die Ausführung nach dem Festschreiben auf einem Continuous Integration-Server.
Frank Shearar
1
"Alle Arten von Tests können in der Toolbox eines guten SW-Ingenieurs verwendet werden, und all diese Szenarien sind unersetzbar." - Ich wünschte, ich könnte mehrmals dafür stimmen! Leute, die denken, dass sie nur ein ideales Testwerkzeug / eine ideale Testmethode finden und überall anwenden können, machen mich müde.
Ptyx
8

Alle Arten von Tests sind sehr wichtig und stellen sicher, dass die verschiedenen Aspekte des Systems den Spezifikationen entsprechen. Um rückwärts zu arbeiten: "Wenn ich einen Testtyp wählen müsste ..." würde ich nicht. Unit-Tests bieten mir ein anderes Feedback als Integrationstests oder interaktive Tests durch eine Person.

Hier ist die Art / der Nutzen der von uns durchgeführten Tests:

  • Unit Testing - stellt sicher, dass die Einheiten die Arbeit ausführen, die wir erwarten. Wir testen sowohl Anbieter- als auch Verbraucherverträge für jede Schnittstelle - und dies ist relativ einfach zu automatisieren. Wir überprüfen auch unsere Randbedingungen usw.
  • Integrationstests - stellen sicher, dass die Einheiten zusammenarbeiten. Dies dient hauptsächlich dazu, unser Design zu testen. Wenn hier etwas kaputt geht, müssen wir unsere Unit-Tests anpassen, um sicherzustellen, dass es nicht wieder vorkommt.
  • Systemprüfung - stellt sicher, dass das System die Anforderungen / Spezifikationen erfüllt. Normalerweise machen die Leute diese Art von Tests.
  • Abnahmetests - Der Kunde überprüft auf diese Weise, ob das Endprodukt die angegebenen Anforderungen erfüllt.

Optionaler, aber empfohlener Test:

  • Testen der Benutzererfahrung: Während wir beim Testen des Systems ein anständiges Feedback erhalten, kann die Vorschau bestimmter Vorabversionen durch die Benutzer des Clients hilfreich sein, um festzustellen, ob Änderungen erforderlich sind, bevor es zu spät ist.

Um zu verstehen, warum Unit Testing einen Vorteil gegenüber Integrationstests hat, müssen Sie die Größenordnungen der zusätzlichen Tests verstehen, die Sie benötigen würden, um umfassend zu sein. Für jedes mögliche Ergebnis für Einheit A muss ein Test durchgeführt werden. Dasselbe gilt für Einheit B. Wenn nun beide für eine vollständigere Lösung zusammenarbeiten, ist die Anzahl der Tests kombinatorisch. Kurz gesagt, um jede Permutation der Interaktion zwischen Einheit A und Einheit B zu testen, benötigen Sie A * B-Tests. Addiere Einheit C und die Anzahl der Tests für das Trio wäre A * B * C.

Hier wird das Konzept von Schnittstellen und Objektgrenzen sehr wichtig. Schnittstellen stellen einen bestimmten Vertrag dar. Ein Implementierer einer Schnittstelle stimmt zu, dass sie sich auf eine bestimmte Weise verhält. Ebenso kann ein Verbraucher stimmt zu einer Schnittstelle , dass sie die Umsetzung in einer bestimmten Art und Weise verwendet werden. Indem Sie einen Test schreiben, der alle Klassen erfasst, die eine Schnittstelle implementieren, können Sie auf einfache Weise testen, ob jede Implementierung die Schnittstellenverträge einhält. Das ist die halbe Wahrheit. Die andere Hälfte besteht darin, die Verbraucherseite zu testen - hier kommen Scheinobjekte ins Spiel. Das Mock ist so konfiguriert, dass sichergestellt ist, dass die Interaktionen immer den Spezifikationen entsprechen. Zu diesem Zeitpunkt sind lediglich einige Integrationstests erforderlich, um sicherzustellen, dass die Implementierungs- / Verbraucherverträge korrekt sind.

Berin Loritsch
quelle
"Systemprüfung - stellt sicher, dass das System die Anforderungen / Spezifikationen erfüllt. Normalerweise wird diese Art von Prüfung durchgeführt." System- / aka Funktions- / aka "End-to-End" - / aka High-Level-Integrationstests sind ebenfalls gut für die Automatisierung.
MiFreidgeim SO-aufhören, böse zu sein
3

Dies sind verschiedene Tools mit unterschiedlichen Zielen:

  • Unit Testing ist ein Designtool (TDD) und eine fast unabdingbare Voraussetzung für das Refactoring.

  • Integrationstests sind großartig, um den Fortschritt des Projekts zu visualisieren und Regressionsfehler zu vermeiden.

Denken Sie daran, dass Sie mit Integrationstests nicht wirklich entwerfen können und mit Komponententests keine Regressionen finden.

Javier
quelle
@ Sie können nicht wirklich mit Integrationstests entwerfen, und Sie werden keine Regressionen mit Komponententests finden. Genau!
Chankey Pathak
Unit-Tests können durch Refactoring verursachte Regressionen feststellen, z. B. eine geänderte Shared-Helper-Methode. Integrationstests sind dafür allerdings viel besser.
StuperUser
Der zweite Punkt über Integrationstests beinhaltet "System / Functional" -Tests (auch "End-to-End" -Tests genannt)
MiFreidgeim SO-aufhören, böse zu sein
Voll und ganz einverstanden; Ein ähnlicher Punkt wurde vor einigen Jahren von Steve Sanderson angesprochen. In der Tabelle "Goal - Strongest technique" (Ziel - Stärkste Technik) in seinem Blogbeitrag 2009 unter blog.stevensanderson.com/2009/08/24/… finden Sie ergänzende Gedanken zu Ihren eigenen hier.
Mark A. Fitzgerald
1

Ich habe Selen ausgiebig für Hygienekontrollen verwendet.

Bei einem großen Web-Verlag, als eine neue Version veröffentlicht wurde, dauerte es in der Regel ungefähr drei Tester in ein oder zwei Stunden, um alle Familien von Websites zu besuchen und sicherzustellen, dass gemäß Testskript alles in Ordnung war. Mit Selenium konnten wir die Tests automatisieren und auf mehrere Computer und Browser verteilen. Derzeit, wenn die Testskripte ausgeführt werden, dauert es ca. 10 Minuten, bis 3 PCs automatisch dasselbe tun UND einen hübschen Bericht ausspucken.

Das Tolle an Selen ist, dass Sie es mit Unit-Testing-Frameworks wie XUnit, TestNG oder MSTest verknüpfen können.

Meiner Erfahrung nach war es äußerst wertvoll, jedoch hängt die Einrichtung von so etwas wirklich von Ihrem Projekt und Ihrem Team ab, sodass der ROI auf jeden Fall variieren wird.

Ryan Hayes
quelle
1

Der beste ROI ist normalerweise der früheste Test, der diese Art von Fehler finden kann.

Unit-Tests sollten die meisten Fehler aufdecken, die sich nur in einer Methode oder möglicherweise in einer Komponente befinden. Es werden Fehler gefunden, die normalerweise innerhalb von Minuten behoben werden können, wobei die Gesamtumschlagszeit weniger als eine Stunde beträgt. SEHR billige Tests, SEHR billige Fehler zu finden und zu beheben! Wenn diese Fehler in den Integrationstest eingegangen sind, kann der Turn-Around eher ein Tag sein (Testläufe finden häufig nachts statt), vorausgesetzt, der Fehler wird nicht von einem anderen Fehler verdeckt. Außerdem wird es wahrscheinlich mehr Bugs geben, da anderer Code gegen den ursprünglichen Buggy-Code geschrieben wurde. Darüber hinaus wirken sich alle Neugestaltungen auf mehr Codeteile aus. Wenn mehr Fehler durchgelassen werden, müssen viele weitere Testläufe durchgeführt werden, bevor der Integrationstest abgeschlossen werden kann. Schlechte Komponententests sind oft das Herzstück von langen, kostspieligen und teuren ProzessenIntegrationszyklen testen. Durch das Überspringen von Unit-Tests wird möglicherweise die Entwicklungszeit halbiert, aber das Testen dauert mindestens drei- bis viermal so lange, das gesamte Projekt wird doppelt so lang und Sie haben immer noch eine geringere Qualität als bei Unit-Tests mit IME.

Integrationstests sind normalerweise die frühesten tatsächlichen Tests, bei denen Integrationsfehler gefunden werden können (obwohl Überprüfungsprozesse einige Fehler finden können, bevor die Software geschrieben wird oder bevor der Code getestet wird). Sie möchten diese Fehler finden, bevor Sie dem Benutzer oder der Veröffentlichung die Software anzeigen, da das Beheben von Fehlern im letzten Moment (oder das Beheben von Fehlern im laufenden Betrieb!) Sehr teuer ist. Sie können diese Fehler nicht früher finden, wenn sie billiger zu beheben wären, da Sie (per Definition) mehrere funktionierende Komponenten für die Integration benötigen. Integrationstests werden verlangsamt, wenn Fehler, die nichts mit interagierenden Teilen zu tun haben (wie kleinere Tippfehler), zuerst behoben werden müssen, bevor die interessanteren Tests überhaupt beginnen können.

Beim Testen der Benutzerakzeptanz wird sichergestellt, dass die Software das tut, was der Kunde wünscht (obwohl er hoffentlich die ganze Zeit involviert war), um das Risiko zu verringern, dass am Ende des Projekts eine große Lücke zwischen den Erwartungen und der tatsächlichen Software entsteht - SEHR teuer !). Wenn Sie dieses Teststadium erreicht haben, sollten Sie wirklich glauben, dass die meisten Fehler in Ihrem Produkt, zumindest im Vergleich zu den technischen Daten, bereits gefunden wurden. Beim Testen der Benutzerakzeptanz geht es mehr darum, sicherzustellen, dass das Produkt den Anforderungen des Kunden entspricht, als dass sichergestellt wird, dass im Vergleich zu den Spezifikationen keine Fehler auftreten.

Wenn ich nur einen Testtyp automatisieren würde, wäre es ein Unit-Test. Integrationstests können manuell durchgeführt werden und wurden von vielen großen Unternehmen über Jahre hinweg auf diese Weise durchgeführt. Es ist zeitaufwändiger, Arbeiten manuell auszuführen, die von einem Computer immer wieder ausgeführt werden können, und für die meisten Projekte weitaus teurer, ganz zu schweigen von langweiligen und fehleranfälligen Aufgaben, die jedoch ausgeführt werden können. Benutzerakzeptanztests werden häufig manuell durchgeführt, da Benutzer häufig nicht wissen, wie sie ihre Tests automatisieren sollen, während sie noch testen, was ihnen wichtig ist. Unit-Tests müssen automatisiert werden. Sie müssen in der Lage sein, alle Unit-Tests innerhalb weniger Sekunden bei Bedarf so häufig wie alle paar Minuten auszuführen. Menschen können sich mit manuellen Tests einfach nicht einmal annähern. Ganz zu schweigen davon, dass Unit-Tests im Code enthalten sind und nicht ausgeführt werden können, ohne sie über Code aufzurufen, dh zu automatisieren.

Beachten Sie, dass dies in erster Linie ein Forum für Entwickler und nicht für Tester ist. Integrationstests werden hauptsächlich von Testern durchgeführt. Unit-Tests werden von Entwicklern implementiert. Natürlich sprechen Entwickler mehr über Komponententests als über andere Testarten. Dies bedeutet nicht, dass sie andere Tests nicht für wichtig halten. Es bedeutet nur, dass sie es nicht wirklich tun (oder es seltener tun).

Ethel Evans
quelle
Vielen Dank vor allem für den letzten Absatz, daran habe ich nicht gedacht.
Bjarke Freund-Hansen
Zu Ihrer Information, ich habe die Antwort aktualisiert, seitdem Sie sie gelesen haben - ich habe festgestellt, dass ich die ursprüngliche Frage nicht genau genug gelesen habe
Ethel Evans
@EthelEvans, Ihre Gründe für Unit-Tests-Prioritäten sind für neue Projekte richtig. Für Legacy-Projekte, die ohne Berücksichtigung der Automatisierung der Testabdeckung erstellt wurden, sind System- / alias Funktions- / alias hochrangige Integrationstests am wichtigsten. Lesen Sie den letzten Teil der Antwort von programmers.stackexchange.com/a/39370/31574 .
MiFreidgeim SO-aufhören, böse zu sein
@MichaelFreidgeim, es kommt letztendlich darauf an, wie stabil die Schnittstellen sind. Die Automatisierung von Tests auf hoher Ebene kann schnell zu unerschwinglichen Wartungskosten führen, wenn sie schnell veraltet sind. In diesem Fall sollten Sie eine niedrigere Stufe automatisieren, um die Stabilität zu erhöhen, und Sondertests (möglicherweise sitzungs- oder checklistenbasiert) für E2E- und Integrationstests durchführen, um unangenehme Kosten für die Automatisierungswartung zu vermeiden. Allerdings verfügen nicht alle Legacy-Projekte über stabile Schnittstellen - insbesondere, wenn sie überarbeitet oder aggressiv umgestaltet werden.
Ethel Evans
1

Ich bin der Meinung, dass Akzeptanztests in diesem Szenario König sind.

Wenn ein Commit Akzeptanztests bricht, muss es aussortiert werden.

Akzeptanztests zeigen an, wo sich Ihre Software befindet, Unit-Tests nicht.

Daher können Unit-Tests ein sehr falsches Sicherheitsgefühl vermitteln.

godelfiend
quelle
0

Die Frage ist nicht so sehr, was wichtiger ist, als was automatisiert und schnell ausgeführt werden kann.

Komponententests zeigen, ob eine kleine Komponente auf bestimmte Weise für einen bestimmten Zweck geeignet ist und in der Regel klein und schnell ausgeführt werden kann. Da sie klein sind, lassen sie sich normalerweise recht einfach automatisieren.

Integrationstests zeigen, ob Komponenten zusammenarbeiten. Sie sind normalerweise viel größer und möglicherweise nicht einfach zu automatisieren. Die Laufzeit kann länger dauern. Es ist von Vorteil, sie automatisch ausführen zu können, aber es ist eine größere Aufgabe, und sie werden sowieso nicht so oft ausgeführt.

Abnahmetests zeigen, ob ein Projekt akzeptabel ist oder nicht. Dies ist normalerweise nicht vollständig automatisierbar (obwohl automatisierte Tests möglicherweise eine Rolle spielen), da es normalerweise nicht möglich ist, die genauen und vollständigen Anforderungen in einer formalen Angelegenheit festzulegen, die weniger kompliziert ist als der Quellcode selbst. Akzeptanztests beinhalten normalerweise, dass potenzielle Benutzer Dinge mit dem System tun und feststellen, dass die Ergebnisse in jeder Hinsicht zufriedenstellend sind, was normalerweise teilweise subjektiv ist. Da Abnahmetests in der Regel einmal ausgeführt werden (verschiedene Kunden möchten normalerweise ihre eigenen separaten Abnahmetests durchführen), lohnt es sich nicht, sie zu automatisieren.

David Thornley
quelle