Sind Unit-Tests wirklich so nützlich? [geschlossen]

98

Ich habe gerade meinen Abschluss in CS gemacht und bin derzeit als Junior .NET Developer (C #, ASP.NET und Web Forms) tätig. Als ich noch auf der Universität war, wurde das Thema Unit Testing zwar behandelt, aber ich habe die Vorteile nie wirklich erkannt. Ich verstehe, was es tun soll, nämlich festzustellen, ob ein Codeblock zur Verwendung geeignet ist oder nicht. Allerdings musste ich vorher noch nie einen Unit-Test schreiben und hatte auch nie das Bedürfnis danach.

Wie bereits erwähnt, entwickle ich normalerweise mit ASP.NET-Webformularen. In letzter Zeit habe ich darüber nachgedacht, einige Komponententests zu schreiben. Aber ich habe ein paar Fragen dazu.

Ich habe gelesen, dass Unit-Tests oft durch das Schreiben von "Mocks" geschehen. Obwohl ich dieses Konzept verstehe, kann ich nicht herausfinden, wie ich Mocks für Websites schreiben soll, die vollständig dynamisch sind und bei denen fast alles von Daten abhängt, die aus einer Datenbank stammen. Zum Beispiel: Ich verwende viele Repeater mit ItemDataBound-Ereignissen usw. (wiederum abhängig von Daten, die "unbekannt" sind).

Frage Nr. 1: Wird das Schreiben von Komponententests für ASP.NET-Webformulare häufig durchgeführt, und wenn ja: Wie löse ich das Problem der "dynamischen Umgebung"?

Wenn ich mich entwickle, mache ich eine Menge Trial-and-Error durch. Das bedeutet nicht, dass ich nicht weiß, was ich tue, aber ich meine, dass ich normalerweise Code schreibe, drücke Ctrl F5und sehe, was passiert. Während dieser Ansatz die meiste Zeit die Arbeit erledigt, habe ich manchmal das Gefühl, dass ich ein wenig ahnungslos bin (aufgrund meiner geringen Erfahrung). Manchmal verschwende ich auch so viel Zeit.

Frage 2: Würden Sie mir raten, mit dem Schreiben von Komponententests zu beginnen? Ich denke, es könnte mir bei der tatsächlichen Implementierung helfen, aber andererseits habe ich das Gefühl, dass es mich verlangsamen könnte.

Jane Doe
quelle
1
Ich möchte nur sagen, die andere Seite davon ist, dass einige Orte sie als Übung benötigen. Ich bin jetzt an einem Ort, an dem wir keinen Code einchecken dürfen, es sei denn, es wird im Rahmen von Unit-Tests behandelt. Es ist daher wichtig zu wissen, dass Sie sie möglicherweise später ausführen müssen, auch wenn Sie nicht an sie glauben. Ich denke, es ist eine nützliche Fähigkeit zu lernen und in Ihrem Arsenal zu haben. Ich werde oft kleine Fehler und Pannen in meinem Code finden, wenn ich die Tests durchführe, fast eine kleine QS-Sitzung mit dir.
Adam
9
Wie genau haben Sie Unit-Tests behandelt, ohne Unit-Tests zu schreiben? War dies eine dieser "Grade yourself" - oder "Design Your Own Curriculum" -Schulen?
JeffO
4
Unit-Tests sind fragwürdig - Ideal für dynamische Sprachen, weniger nützlich, je strenger Ihre Sprache ist, aber TESTS ERSTELLEN. Es müssen keine Unit-Tests sein, aber Sie sollten wirklich Integrationstests haben, die Sie mit JUnit ausführen können. Diese sind sehr nützlich.
Bill K
13
-1 Entschuldigung, ich bin alle für gute Argumente, auch wenn ich nicht einverstanden bin, aber das ist einfach falsch. Niemand behauptet, "Unit-Tests dienen dazu, Bugs in neuem Code zu finden", also ist das ein Strohmann - Unit-Tests dienen dazu, Regressionen zu erkennen . Und das Dijkstra-Zitat wird aus dem Kontext gerissen - der Kontext ist, dass das Testen sinnlos ist, wenn Sie eine formale Spezifikation Ihres Problems haben .
Sleske
9
msgstr "Unit - Tests dienen zum Auffangen von Regressionen". Nein. Automatisierte Tests dienen zum Auffangen von Regressionen. Bei Regressionen müssen dieselben Tests immer mehrere hundert Mal ausgeführt werden, daher lohnt es sich, sie zu automatisieren. Leider beschäftigen sich viele der Antworten und Kommentare zu dieser Frage wirklich mit dem Thema "Sind automatisierte Tests hilfreich?". Unit-Tests können eine Form von automatisierten Tests sein, haben jedoch einen völlig anderen Schwerpunkt. Ich bin sicher der Meinung, dass automatisierte Tests Gold wert sind, aber das sollte nicht als Argument zur Rechtfertigung von Unit-Tests (oder TDD) herangezogen werden.
njr101

Antworten:

124

Meiner Meinung nach: Ja, das sind sie, und das solltest du.

  1. Sie geben Ihnen Vertrauen in die Änderungen, die Sie vornehmen (alles andere funktioniert noch). Dieses Vertrauen ist es, was Sie brauchen, um den Code zu formen, sonst könnten Sie Angst haben, Dinge zu ändern.

  2. Sie verbessern Ihren Code. Die einfachsten Fehler werden bei den Unit-Tests frühzeitig erkannt. Das frühzeitige Erkennen und Beheben von Fehlern ist immer günstiger als das spätere Beheben, z. B. wenn die Anwendung in der Produktion ist.

  3. Sie dienen anderen Entwicklern als Dokumentation zur Funktionsweise und Verwendung Ihres Codes.

Das erste Problem, mit dem Sie konfrontiert werden, ist, dass ASP.NET an sich Ihnen nicht hilft, Komponententests zu schreiben - tatsächlich funktioniert es gegen Sie. Wenn Sie eine Wahl haben, starten Sie die Verwendung von ASP.NET MVC , das unter Berücksichtigung von Komponententests erstellt wurde. Wenn Sie ASP.NET MVC nicht verwenden können, sollten Sie das MVP- Muster in ASP.NET verwenden, damit Sie zumindest Ihre Logik problemlos testen können.

Außerdem müssen Sie sich nur mit dem Schreiben von Komponententests auskennen. Wenn Sie TDD üben, wird Ihr Code testbar erstellt - mit anderen Worten, schön und sauber.

Ich würde dir raten, das Programm zu üben und zu paaren. Während des Lesens:

Oder für einen ersten Überblick:

KeesDijk
quelle
4
Nachdem ich gerade mit Unit-Tests angefangen hatte, musste ich zustimmen. Es ist nicht nur eine gute Angewohnheit und sehr nützlich in Kombination mit einem TDD-Ansatz, sondern es minimiert auch so viel Zeit. Ich denke nicht, dass meine Projekte so nützlich sein könnten, wenn ich nicht in der Lage wäre, nur einen Komponententest durchzuführen und zu überprüfen, ob alles richtig funktioniert, selbst nachdem ich eine neue Funktion hinzugefügt oder einen Fehler behoben habe. Ich kann mir nicht vorstellen, Regressionstests auf andere Weise durchzuführen.
Kwelch
21
Wenn Unit-Tests als Dokumentation dienen, stimmt etwas nicht. Lesen Sie 500 Codezeilen, um zu verstehen, wie 5 Codezeilen rückwärts funktionieren.
Coder
4
@Coder: Wenn Sie Methoden auf höherer Ebene testen, sind wesentlich mehr als 5 Codezeilen erforderlich.
7
@coder: Die Dokumentation einer Klasse informiert Sie über die Dienste, die die Klasseninstanzen bereitstellen. Sie erhalten weniger Informationen darüber, wie die Instanzen dieser Klasse im größeren Kontext verwendet werden, d. H. Bei der Interaktion zwischen Objekten. Tests geben Ihnen in einigen Fällen einen typischen Code für die Interaktion, der als Ausgangspunkt so wertvoll war, dass ich ihn oft nicht einmal zählen kann.
Stefano Borini
21
@Coder: Es dokumentiert nicht, was der Code tut, es dokumentiert die in diesem Code enthaltenen Annahmen , dh warum und wann er funktionieren soll. Wenn die zugrunde liegenden Annahmen durch eine Änderung des SUT ungültig werden, sollten ein oder mehrere Komponententests fehlschlagen. Dies ersetzt keine übergeordnete Design- / Architekturdokumentation oder sogar XML-Dokumente, deckt jedoch ab, was diese Dinge niemals können.
Aaronaught
95

Nein.

Das Konzept der Komponententests basiert auf einer Prämisse, von der seit der Erfindung der Komponententests bekannt war, dass sie falsch sind: Die Idee, dass Tests beweisen können, dass Ihr Code korrekt ist.

Viele Tests zu haben, die alle bestanden haben, beweist eines und nur eines: Sie haben viele Tests, die alle bestanden haben. Es wird nicht bewiesen, dass das, was die Tests testen, mit der Spezifikation übereinstimmt. Es beweist nicht, dass Ihr Code frei von Fehlern ist, die Sie beim Schreiben der Tests nie berücksichtigt haben. (Und die Dinge, die Sie zu testen dachten, waren die möglichen Probleme, auf die Sie sich konzentrierten, also haben Sie sie wahrscheinlich trotzdem richtig gemacht!) Und nicht zuletzt beweist es nicht, dass die Tests, die selbst Code sind, sind frei von Fehlern. (Folgen Sie dem letzten bis zu seiner logischen Schlussfolgerung und Sie landen mit Schildkröten ganz unten .)

Djikstra hat das Konzept der Korrektheitsprüfung bereits 1988 verworfen , und das, was er geschrieben hat, ist bis heute gültig:

Es ist nun zwei Jahrzehnte her, seit darauf hingewiesen wurde, dass Programmtests das Vorhandensein von Fehlern überzeugend nachweisen können, ihre Abwesenheit jedoch niemals nachweisen können. Nachdem der Softwareentwickler diese wohlbekannte Bemerkung ausführlich zitiert hat, kehrt er zur Tagesordnung zurück und verfeinert weiterhin seine Teststrategien, genau wie der Alchemist von einst, der seine chrysokosmischen Reinigungen weiter verfeinert hat.

Das andere Problem beim Komponententest besteht darin, dass eine enge Kopplung zwischen Ihrem Code und der Testsuite hergestellt wird. Wenn Sie den Code ändern, würden Sie erwarten, dass einige Fehler auftauchen, die einige Tests zum Erliegen bringen würden. Wenn Sie jedoch den Code ändern, weil sich die Anforderungen selbst geändert haben, werden viele Tests fehlschlagen, und Sie müssen manuell über jeden einzelnen Test entscheiden, ob der Test noch gültig ist oder nicht. (Und es ist auch möglich, dass ein vorhandener Test, der ungültig sein sollte , noch besteht , obwohl er seltener vorkommt, weil Sie vergessen haben, etwas zu ändern, das geändert werden musste.)

Unit-Tests sind das Neueste in einer langen Reihe von Entwicklungsmodellen, die versprechen, das Schreiben von Arbeitscode zu vereinfachen, ohne wirklich ein guter Programmierer zu sein. Keiner von ihnen hat es jemals geschafft, sein Versprechen zu halten, und dieser auch nicht. Es gibt einfach keine Abkürzung, um tatsächlich zu wissen, wie man Arbeitscode schreibt .

Es gibt einige Berichte, wonach automatisierte Tests wirklich nützlich sind, wenn Stabilität und Zuverlässigkeit von größter Bedeutung sind. Zum Beispiel das SQLite-Datenbankprojekt. Aber was es braucht , ihre Maß an Zuverlässigkeit zu erreichen , ist in hohem Maße unwirtschaftlich für die meisten Projekte: ein Test-zu-Ist-SQLite-Code - Verhältnis von fast 1200: 1. Die meisten Projekte können sich das nicht leisten und brauchen es auch nicht.

Mason Wheeler
quelle
69
Es zeigt, dass sich Ihr Code für diese Tests korrekt verhält . Es ist eine verdammte Menge, wenn Sie mich fragen.
Stefano Borini
111
Wer glaubt heute eigentlich, Unit Tests seien "Proof-of-Correction"? Niemand sollte das denken. Sie haben Recht, dass sie nur beweisen, dass diese Tests bestanden wurden, aber das ist ein Datenpunkt mehr als vor dem Schreiben der Komponententests. Sie müssen auf vielen verschiedenen Ebenen testen, um sich einen Überblick über die Qualität Ihres Codes zu verschaffen. Unit-Tests beweisen nicht, dass Ihr Code fehlerfrei ist, aber sie erhöhen Ihr Vertrauen (oder sollten es tun), dass der Code das tut, wofür Sie ihn entworfen haben, und auch morgen noch das tut, was er heute tut.
Bryan Oakley
40
> but if the test itself is buggy, then you have false confidenceund wenn der manuelle Tester seine Arbeit nicht richtig ausführt, haben Sie auch falsches Vertrauen.
Stefano Borini
33
@ MasonWheeler: Entschuldigung, Mason, ich bin nicht überzeugt. In mehr als ein paar Jahrzehnten der Programmierung glaube ich nicht, dass ich jemals einen Fall gesehen habe, in dem ein Test ein falsches Sicherheitsgefühl vermittelt hat. Vielleicht haben einige von ihnen das getan und wir haben sie behoben, aber die Kosten für diese Komponententests überwogen in keiner Weise die enormen Vorteile, die sie mit sich bringen. Wenn Sie in der Lage sind, Code zu schreiben, ohne ihn auf Geräteebene zu testen, bin ich beeindruckt, aber die große Mehrheit der Programmierer ist nicht in der Lage, dies konsistent zu tun.
Bryan Oakley
41
Wenn Sie einen Buggy-Test geschrieben haben, bei dem Ihr Code bestanden wurde, ist Ihr Code wahrscheinlich auch fehlerhaft. Die Wahrscheinlichkeit, Buggy-Code und einen Buggy-Test zu schreiben, ist weitaus geringer als bei Buggy-Code allein. Unit-Tests sind kein Allheilmittel. Sie sind eine gute zusätzliche Schicht (wenn sinnvoll), um die Belastung der manuellen Tester zu verringern.
Telastyn
60

Wenn Sie jemals den Vorteil gesehen haben, eine Hauptmethode zum Testen eines kleinen Teils des Codes für die Schule zu schreiben, ist Unit-Testing die professionelle / Enterprise-Version derselben Praxis.

Stellen Sie sich auch den Aufwand vor, den Code zu erstellen, Ihren lokalen Webserver zu starten, zu der betreffenden Seite zu navigieren, die Daten einzugeben oder die Eingabe auf den richtigen Test-Startwert zu setzen, das Formular abzusenden und die Ergebnisse zu analysieren ... im Vergleich zum Erstellen und Schlagen die Schaltfläche nUnit run.

Hier ist auch ein lustiges Bild ... Bildbeschreibung hier eingeben

Ich fand dieses Bild hier:
http://www.howtogeek.com/102420/geeks-versus-non-geeks-when-doing-repetitive-tasks-funny-chart/

Heath Lilley
quelle
2
Ja, du kannst. Isolieren Sie die Webebene in Ihren Komponententests, um die Webkonfiguration (URLs, Eingabevalidierung usw.) zu testen. Durch Stubbing der Web- und Datenbankebene können Sie die Geschäftsschicht ohne Datenbank oder Webserver testen. Ich benutze Dbunit, um meine DB zu testen. Wenn Sie möchten, können Sie immer noch vollständige Integrationstests durchführen, aber das mache ich als spezifische Aufgabe nach der Entwicklung.
Heath Lilley
12
Nette Grafik, aber die Skala stimmt nicht. Wie ich in meiner Antwort ausgeführt habe, erfordert die vollständige Testabdeckung von SQLite ungefähr 1200-mal mehr Code in Tests als der tatsächliche Code im Produkt. Und selbst wenn Sie nicht sind , dass obsessiv über eine vollständige Abdeckung, müssen Sie noch einige Male mehr Tests als Produkt auch in Ihren Tests einen nützlichen Deckungsgrad nähern. Um hier genau zu sein, müsste der vertikale Teil dieser roten Linie für ungefähr 3 Seitenlängen immer weiter nach oben und nach oben gehen.
Mason Wheeler
27
@MasonWheeler Das ist ein sehr schönes Pferd, das Sie schlagen, ich glaube, es ist zwar gestorben ... SQLite hat so viele Tests, weil es eine verdammte Datenbank ist. Ich möchte sicherstellen, dass das funktioniert. Als weiteres Beispiel hat das Silverstripe-Framework ein Verhältnis von Tests zu Code von nahezu 1: 1, sodass SQLite nicht repräsentativ ist.
Aatch
15
@MasonWheeler Sie scheitern am ersten Paradoxon von Zeno . Wenn Sie dieses Bild auf die Teststufe von SQLite skalieren möchten, muss die X-Achse auch um das 100-fache ihrer aktuellen Länge erweitert werden.
Izkata
2
Dies gilt insbesondere, wenn Sie ein Back-End-Entwickler sind, der nicht die Zeit hat, eine Schwarzweiß-Webseite zu erstellen, damit Sie Ihre Back-End-Logik testen können. Alles, was ich tun muss, um Scheinanforderungen und Sitzungsobjekte bereitzustellen und meine Controller durch einen Komponententest zu führen, und am Ende alles, was ich weiß, ob es richtig oder falsch ist. Wenn Sie DI verwenden, fügen Sie einfach ein DAO ein, das mit einer In-Memory-Datenbank interagiert, damit sich Ihre Datenbank nicht ändert, oder werfen Sie einfach ein Exceptionund fangen Sie es ab, damit Ihre Daten nicht festgeschrieben werden. Ich sage JA zu Unit-Tests.
Varun Achar
49

Unit Testing hat heutzutage etwas Mystisches an sich. Die Leute behandeln es so, als wäre eine 100% ige Testabdeckung ein heiliger Gral, und als wäre Unit-Testing der einzig wahre Weg, Software zu entwickeln.

Sie verpassen den Punkt.

Unit Testing ist nicht die Antwort. Testen ist.

Wann immer diese Diskussion auftaucht, wird jemand (oft sogar ich) Dijkstra's Zitat vorlesen: "Programmtests können das Vorhandensein von Fehlern nachweisen, aber niemals deren Abwesenheit." Dijkstra hat recht: Tests reichen nicht aus, um zu beweisen, dass Software wie beabsichtigt funktioniert. Aber es ist notwendig : auf einer bestimmten Ebene, muss es möglich sein , zu zeigen , dass die Software tut , was Sie wollen es.

Viele Leute testen von Hand. Selbst überzeugte TDD-Enthusiasten führen manuelle Tests durch, obwohl sie dies manchmal nicht zugeben. Es kann nicht geholfen werden: Kurz bevor Sie in den Konferenzraum gehen, um Ihrem Kunden / Chef / Investor / etc. Ihre Software vorzuführen, werden Sie sie von Hand durchgehen, um sicherzustellen, dass sie funktioniert. Daran ist nichts auszusetzen, und in der Tat wäre es verrückt, zu erwarten, dass alles reibungslos abläuft, ohne es manuell durchlaufen zu müssen - das heißt, es zu testen -, selbst wenn Sie eine 100% ige Testabdeckung und größtes Vertrauen in Ihre Tests haben .

Manuelle Tests sind jedoch nur selten ausreichend , auch wenn sie zum Erstellen von Software erforderlich sind . Warum? Weil manuelles Testen mühsam und zeitaufwändig ist und vom Menschen durchgeführt wird. Und Menschen sind notorisch schlecht darin, mühsame und zeitraubende Aufgaben zu erledigen: Sie meiden es, wenn immer es möglich ist, und sie tun es oft nicht gut, wenn sie dazu gezwungen werden.

Maschinen hingegen sind hervorragend in der Lage, mühsame und zeitaufwändige Aufgaben auszuführen. Denn dafür wurden Computer erfunden.

Daher ist das Testen von entscheidender Bedeutung, und automatisiertes Testen ist der einzig sinnvolle Weg, um sicherzustellen, dass Ihre Tests konsistent durchgeführt werden. Bei der Entwicklung der Software ist es wichtig, diese zu testen und erneut zu testen. In einer anderen Antwort wird auf die Bedeutung von Regressionstests hingewiesen . Aufgrund der Komplexität von Softwaresystemen führen häufig scheinbar harmlose Änderungen an einem Teil des Systems zu unbeabsichtigten Änderungen (dh Fehlern) in anderen Teilen des Systems. Sie können diese unbeabsichtigten Änderungen nicht ohne irgendeine Form von Test feststellen. Und wenn Sie zuverlässige Daten über Ihre Tests haben möchten, müssen Sie diese systematisch durchführen, was bedeutet, dass Sie über eine Art automatisiertes Testsystem verfügen müssen.

Was hat das alles mit Unit-Tests zu tun? Nun, aufgrund ihrer Natur werden Unit-Tests von der Maschine und nicht von einem Menschen durchgeführt. Daher haben viele Menschen den falschen Eindruck, dass automatisiertes Testen dem Testen von Einheiten gleichkommt . Das stimmt aber nicht: Unit-Tests sind nur kleine automatisierte Tests.

Was ist nun der Wert bei besonders kleinen automatisierten Tests? Der Vorteil besteht darin, dass sie Komponenten eines Softwaresystems isoliert testen , was eine genauere Ausrichtung der Tests ermöglicht und das Debuggen unterstützt . Aber Unit - Tests bedeutet nicht intrinsisch höhere Qualitätstests . Dies führt häufig zu höheren Qualitätstests, da Software mit einer genaueren Detaillierung abgedeckt wird. Es ist jedoch möglich, das Verhalten nur eines vollständigen Systems und nicht seiner zusammengesetzten Teile vollständig zu testen und es dennoch gründlich zu testen.

Aber selbst bei einer 100% igen Abdeckung durch Einheitentests kann ein System möglicherweise nicht gründlich getestet werden. Weil einzelne Komponenten möglicherweise isoliert einwandfrei funktionieren, aber dennoch versagen, wenn sie zusammen verwendet werden. So Unit - Tests, während sehr nützlich, reicht nicht aus , dass die Software funktioniert , um sicherzustellen , wie erwartet. Tatsächlich ergänzen viele Entwickler Komponententests mit automatisierten Integrationstests, automatisierten Funktionstests und manuellen Tests.

Wenn Sie in Komponententests keinen Nutzen sehen, können Sie am besten mit einer anderen Art von automatisiertem Test beginnen. In einer Webumgebung bietet die Verwendung eines Testtools für die Browserautomatisierung wie Selen oft einen großen Gewinn für eine relativ kleine Investition. Sobald Sie Ihre Zehen ins Wasser getaucht haben, können Sie leichter erkennen, wie hilfreich automatisierte Tests sind. Sobald Sie automatisierte Tests durchgeführt haben, sind Komponententests weitaus sinnvoller, da sie eine schnellere Abwicklung ermöglichen als umfangreiche Integrations- oder End-to-End-Tests, da Sie Tests nur auf die Komponente ausrichten können, an der Sie gerade arbeiten.

TL; DR: Mach dir noch keine Gedanken über Unit-Tests . Sorgen Sie sich nur darum , Ihre Software zuerst zu testen .

Daniel Pryden
quelle
Unit-Tests werden auch von Menschen geschrieben und können falsch sein.
Seun Osewa
41

Es hängt davon ab, ob

Dies ist eine Antwort, die Sie bei der Softwareentwicklung sicherlich häufig sehen werden, aber der Nutzen von Komponententests hängt wirklich davon ab, wie gut sie geschrieben sind. Eine nominelle Anzahl von Komponententests, die die Funktionalität der Anwendung für Regressionstests überprüfen, kann sehr nützlich sein. Eine Vielzahl einfacher Tests, mit denen die Rückkehr von Funktionen überprüft wird, kann jedoch unbrauchbar sein und ein falsches Sicherheitsgefühl vermitteln, da die Anwendung "viele Komponententests" enthält.

Darüber hinaus ist Ihre Zeit als Entwickler wertvoll und die Zeit, die Sie für das Schreiben von Komponententests aufgewendet haben, ist Zeit, die Sie nicht für das Schreiben neuer Funktionen aufgewendet haben. Auch dies bedeutet nicht, dass Sie keine Komponententests schreiben sollten, aber benötigt jede öffentliche Funktion einen Komponententest? Ich würde vorschlagen, dass die Antwort nein ist. Muss der Code, der die Benutzereingabevalidierung durchführt, einmal getestet werden? Sehr wahrscheinlich, da es sich bei Anwendungen um einen häufigen Fehler handelt.

Dies ist einer der Bereiche, in denen Erfahrung zum Tragen kommt. Mit der Zeit werden Sie die Teile der Anwendung erkennen, die vom Komponententest profitieren könnten, aber es wird eine Weile dauern, bis Sie diesen Punkt erreichen.

rjzii
quelle
Das ist ein guter Punkt. Sie müssen wissen, wie man gute Tests schreibt, die den Wert des SUT erfassen.
Andy
3
Dies beschreibt im Wesentlichen, wie ich Unit-Tests lernen konnte - schreiben Sie zuerst Tests, um die wichtigsten / zerbrechlichsten Situationen abzudecken, und fügen Sie dann weitere Tests hinzu, wenn sich Ihre Annahmen als falsch herausstellten (ich dachte, etwas könnte "nie scheitern", aber es tat es). .
Brendan Long
38

Projekte für Universitätsklassen unterscheiden sich erheblich von Geschäftsanwendungen, die Sie bei Ihrer Arbeit schreiben. Der Unterschied ist die Lebensdauer. Wie lange "lebt" das Hochschulprojekt? In den meisten Fällen beginnt es, wenn Sie die erste Codezeile schreiben, und endet, wenn Sie Ihre Note erhalten. Man könnte sagen, dass es effektiv nur für die Zeit der Implementierung lebt. "Release" ist in der Regel gleich "Tod".

Software, die für Unternehmen entwickelt wurde, übertrifft den Release-Death-Point des Universitätsprojekts und lebt so lange, wie Unternehmen dies benötigen. Welches ist sehr lang . Wenn es um Geld geht, wird niemand einen Cent für "cooleren und ordentlicheren Code" ausgeben. Wenn Software, die vor 25 Jahren in C geschrieben wurde, noch funktioniert und gut genug ist (wie von den Anforderungen des Geschäftsinhabers verstanden), müssen Sie sie warten (neue Funktionen hinzufügen, alte verbessern - Quellcode ändern ).

Wir kommen zu einem sehr wichtigen Punkt - der Regression . An dem Ort, an dem ich arbeite, haben wir zwei Teams, die zwei Apps warten. eine, die vor ungefähr 5-6 Jahren mit sehr wenig Code-Test-Berichterstattung * geschrieben wurde, und die zweite, neuere Version der ersten Anwendung mit einer vollständigen Testsuite (Unit, Integration und was sonst nicht). Beide Teams haben engagierte manuelle (menschliche) Tester. Möchten Sie wissen, wie lange es dauert, bis eine neue, recht grundlegende Funktion für das erste Team eingeführt wird? 3 bis 4 Wochen. Die Hälfte dieser Zeit ist "Überprüfen, ob alles andere noch funktioniert". Dies ist eine geschäftige Zeit für manuelle Tester. Die Telefone klingeln, die Leute sind verärgert, etwas ist wieder kaputt. Das zweite Team kümmert sich in der Regel in weniger als drei Tagen um solche Probleme.

Ich sage auf keinen Fall, dass Unit-Tests Ihre Code-Fehler anfällig, korrekt oder andere ausgefallene Wörter machen, die Ihnen einfallen können. Weder sie machen Käfer auf magische Weise verschwinden. In Kombination mit anderen Methoden des automatisierten Softwaretests können Sie Ihre Anwendungen jedoch viel besser warten, als dies sonst der Fall gewesen wäre. Dies ist ein großer Gewinn.

Und zu guter Letzt ein Kommentar von Brian, von dem ich denke, dass er das ganze Thema betrifft:

(...) Sie erhöhen Ihr Vertrauen (oder sollten es tun ...), dass der Code das tut, wofür Sie ihn entworfen haben, und dass er auch morgen das tut, was er heute tut.

Denn zwischen heute und morgen könnte jemand winzige Änderungen vornehmen, die zum Absturz des ach so wichtigen Berichtsgeneratorcodes führen. Tests drücken die Wahrscheinlichkeit aus, dass Sie dies herausfinden, bevor Ihr Kunde ein wenig an Ihrer Seite tut.

* Sie führen langsam immer mehr Tests in ihre Codebasis ein, aber wir alle wissen, wie dieses Zeug normalerweise aussieht.

km
quelle
10
+1000 für die Verknüpfung mit Software_Regression. Colleges stellen Unit-Tests als etwas heraus, das Sie aus purem Glauben heraus tun müssen, ohne im Detail zu erklären, dass es eine Krankheit gibt, die verhindert und kontrolliert werden muss, und dass diese Krankheit als Regression bezeichnet wird . (Dann gibt es das Problem, dass Regressionstests etwas ganz anderes sind als Unit-Tests, denn das einzige, was ich gut erklärt habe, ist das kostenlose Beispiel aus diesem Buch. )
ZJR
25

Beim Schreiben von Komponententests für ASP.NET-Webformulare wird häufig Folgendes ausgeführt: Wie behebe ich das Problem der "dynamischen Umgebung"?

Es wird nicht oft gemacht. Mit UI-Elementen zu arbeiten ist nicht das, was Unit-Tests gut können, da es keine großartige Möglichkeit gibt, programmgesteuert zu überprüfen, ob die richtigen Dinge an den richtigen Stellen auf dem Bildschirm landen.

Würden Sie mir raten, Unit-Tests zu schreiben? Ich denke, es könnte mir bei der tatsächlichen Implementierung helfen, aber andererseits habe ich das Gefühl, dass es mich verlangsamen könnte.

Gegebenenfalls ja. Sie können sehr hilfreich sein, um bestimmte Fälle auf wiederholbare Weise zu überprüfen. Sie wirken als Reibung gegen störende Änderungen und als Ausfallsicherung, wenn Sie bessere Änderungen vornehmen.

Eine Sache zu beachten ist, dass sie Sie in der Regel verlangsamen.

Das ist okay.

Wenn Sie jetzt ein wenig Zeit investieren, können Sie in Zukunft Zeit sparen, da sie einige Fehler erkennen, das Wiederauftreten einiger Fehler verhindern und es Ihnen ermöglichen, andere Verbesserungen im Code vorzunehmen, damit dieser nicht verrottet.

Telastyn
quelle
8
+1 für die tatsächliche Beantwortung des Anwendungsfalls der Frage! Alle anderen sprangen auf den "Unit Test" Teil und vergaßen den "ASP.NET Web
Forms
1
Dies ist eine großartige Antwort und verdient mehr Gegenstimmen. Der Grund dafür ist, dass Sie die Fragen beantwortet haben und ehrlich über die Verlangsamung des Entwicklers nachgedacht haben und nicht versprechen, dass jeder Fehler abgefangen oder verhindert wird absolut wahr.
Mantorok
11

Ich habe gerade meinen Abschluss in CS gemacht und arbeite derzeit als Junior .NET-Entwickler (in C # und normalerweise ASP.NET, Web Forms - nicht ASP.NET MVC). Als ich noch auf der Universität war, wurde das Thema Unit Testing zwar behandelt, aber ich habe die Vorteile nie wirklich erkannt.

Das liegt daran, dass Sie nie groß programmiert haben.

Ich verstehe, was es tun soll - bestimmen, ob ein Codeblock für die Verwendung geeignet ist oder nicht - aber ich musste noch nie einen Unit-Test schreiben. (noch> habe ich jemals das Bedürfnis verspürt ..)

Schreiben von Unit-Tests zwingt Ihren Code, sich an eine bestimmte mentale Struktur anzupassen, die überprüfbar, gut dokumentiert und zuverlässig ist. Es ist viel mehr als das, was Sie behaupten.

-Ich habe gelesen, dass Unit-Tests oft durch das Schreiben von "Mocks" geschehen. Obwohl ich dieses Konzept verstehe, kann ich nicht herausfinden, wie ich Mocks für Websites schreiben soll, die vollständig dynamisch sind und bei denen fast alles von Daten abhängt, die aus einer Datenbank stammen.

den Datenbankzugriff mit einer Scheinklasse verspotten, die Modellklassen zurückgibt, die mit gut definierten, fest codierten Daten gefüllt sind. Oder füllen Sie eine Testdatenbank mit Fixture-Daten und arbeiten Sie von dort aus.

- Würdet ihr mir raten, Unit-Tests zu schreiben?

Auf jedenfall. Lesen Sie zuerst Becks "Test Driven Development" .

Ich denke, es könnte mir bei der tatsächlichen Implementierung helfen, aber andererseits habe ich das Gefühl, dass es mich verlangsamen könnte.

Es verlangsamt dich jetzt. Aber wenn Sie stundenlang statt tagelang debuggen müssen, werden Sie es sich anders überlegen.

Jeder Rat wird geschätzt :)

Prüfung. Vertrau mir. Leider muss es auch eine Verwaltungsrichtlinie sein, aber das spart Zeit. Tests bleiben, sie sind da, jetzt und in Zukunft. Wenn Sie die Plattform wechseln und die Tests ausführen und diese weiterhin funktionieren, wissen Sie , dass Ihre Inhalte wie erwartet funktionieren.

Stefano Borini
quelle
8

Edit: Ich bin natürlich dem TDD Pro / Contra-Haufen beigetreten und habe Frage 1 übersprungen:

1 - Implementieren von Komponententests in ASP.net-Webformularen:

Zuallererst, wenn Sie denken, dass Sie sie dazu bringen können, mit MVC zu arbeiten, kämpfen Sie dafür wie ein tollwütiger Höhlenbär. Als Front-End- / UI-Entwickler habe ich mit .net MVC aufgehört, .net zu hassen, damit ich mich besser darauf konzentrieren kann, jede Java-Weblösung zu hassen, auf die ich jemals gestoßen bin. Unit-Tests sind problematisch, da Webformulare die Grenzen zwischen Server und Client wirklich verwischen. Bei jedem Versuch, Unit-Tests durchzuführen, würde ich den Fokus auf Datenmanipulation legen und (hoffentlich) annehmen, dass Webforms die Normalisierung der Benutzereingaben für Sie unter der Haube erledigt.

2 - Zu der Frage, ob sich Unit-Tests überhaupt lohnen:

Okay, vollständige Offenlegung:

  • Ich bin größtenteils Autodidakt. Meine formale Ausbildung besteht darin, ein JavaScript, ein PHP und eine C # -Klasse zu mögen und meine eigene persönliche Studie der OOP-Prinzipien und das Lesen von Dingen wie Design Patterns.

Jedoch,

  • Ich schreibe hauptsächlich für das clientseitige Web und der eigentliche Programmierteil davon ist in einer der schnellsten und lockersten Sprachen, was dynamische Typisierung, erstklassige Funktionen und Objektveränderlichkeit angeht.

Das heißt, ich schreibe nicht für denselben Compiler oder dieselbe virtuelle Maschine. Ich schreibe für 4-20 verschiedene Interpretationen von drei Sprachen (ja, zwei von ihnen sind lediglich deklarativ, bestimmen aber auch den grundlegenden physischen Raum der Benutzeroberfläche, mit der ich manchmal auf unterschiedliche Weise arbeite) und tue dies, seit die Interpretationen a waren viel vielfältiger als heute. Und nein, ich bin nicht irgendein Kind, das JQuery für Einweg-Apps einsteckt. Ich helfe beim Aufbau und bei der Pflege von ziemlich anspruchsvollem Material mit viel Komplexität der Benutzeroberflächenelemente.

Also ja, hier und da gibt es viele Möglichkeiten für ein paar Optimierungen, um eine massive Kaskade von Fehlern zu erzeugen, wenn Ihre Designfähigkeiten vollkommen beschissen sind oder Sie mittelmäßige Entwickler in großen Mengen mit 1-2 Qualitätsproblemen bei Entwicklern bewerfen.

Ich verstehe, was TDD für Sie tun soll: Bei den Tests geht es wirklich eher darum, Sie dazu zu zwingen, das Design genauer in Betracht zu ziehen und sich auf die Anforderungen zu konzentrieren. Gerecht genug, aber das Problem dabei ist, dass es das, was Sie tun sollten, das Entwerfen für eine Schnittstelle, auf subtile, aber grundlegend andere Weise, das Entwerfen für Tests einer Schnittstelle, untergräbt. Der Unterschied für mich besteht darin, ein klares Bild zu zeichnen, das Mama nicht so schnell erraten und die ganze Seite mit Grün füllen muss, damit Sie das erste Kind sein können, das seine Buntstifte auf den Tisch schlägt und "Fertig!" Ruft. " Indem Sie die Priorität auf die Ergebnisse über Prozess und Design verlagern, fördern Sie im Grunde genommen die weitere Implementierung von Garbage Code, der in der Regel die Ursache Ihrer Probleme war.

Und dann gibt es natürlich noch den oft gepriesenen Nebeneffekt der Komponententests, mit dem Sie Regressionsfehler erkennen können. Die Befürworter von TDD neigen dazu, sich ein wenig darüber Gedanken zu machen, ob dies das eigentliche Ziel ist oder nur eine raffinierte Nebenwirkung, IMO Code, insbesondere in einer dynamischeren Sprache wie JavaScript, in der die Annahme, dass Sie sogar jedes mögliche Szenario in einer langen Kette von Abhängigkeiten vorhersagen können, töricht ist.

Es gibt einen Platz für automatisierte Tests in JS, aber eine viel bessere Nutzung Ihrer Zeit als das Anhängen eines Komponententests an jede einzelne "Einheit" Ihres Codes, die mit einer anderen in Kontakt kommt, stellt sicher, dass Sie nicht über eine Menge verfügen Müllobjekte, die Arbeit duplizieren oder deren beabsichtigte Verwendung dort in erster Linie semantisch mehrdeutig ist. Sie folgen dem DRY-Prinzip. Sie abstrahieren Dinge für die Wiederverwendung / Portabilität, wenn der Wert davon offensichtlich wird (und nicht eine Minute zuvor). Sie etablieren konsistente Prozesse und Methoden, um Dinge eher nach dem Prinzip der Zuckerbrot als nach dem Prinzip der Peitsche zu machen (dh es ist zu einfach, Ihre Sachen richtig zu verwenden, um sich die Mühe zu machen, sie falsch zu machen). Und aus Liebe zu allem, was Sie tun und lassen wollen, lassen Sie sich niemals auf massiv kaskadierende Vererbungsschemata mit Anti-Mustern als Mittel zur Wiederverwendung von Code ein.

All dies hat mir geholfen, schwer zu diagnostizierende Fehler in meinem Code auf eine ernsthafte Art und Weise zu reduzieren, und Sie können darauf vertrauen, dass dies eine große Priorität für jemanden ist, der als Entwickler mit einem Browsersatz aufkam, der Ihnen nichts Besseres mitteilte als " uh, es ist ein Problem mit einem Objekt vom Typ 'Objekt' bei dieser imaginären Zeilennummer in einer nicht angegebenen Datei aufgetreten. " (gee, danke IE6) TDD würde in meiner Arbeit diese Dinge nicht fördern. Es würde den Fokus auf 100% Ergebnisse während des Prozesses verlagern, bei dem es nicht wirklich darauf ankommt, was zwischen Punkt A und B liegt, solange es funktioniert. Es ist eine Zeitverschwendung, die besser darauf abzielt, sicherzustellen, dass Ihre Daten lesbar, tragbar und einfach zu ändern sind, ohne dass es zu großen Verwirrungen kommt.

Oder vielleicht bin ich nur zu nervös in Bezug auf das Paradigma, in dem ich verwurzelt bin, aber meiner Meinung nach ist es viel effektiver, die Zeit zu nutzen, als deinen Hintern zu bedecken, wenn du oder alle anderen auf deiner Seite sind Team macht es falsch. Und nichts sollte Sie dazu zwingen, über Design nachzudenken, nur um Dinge umzusetzen. Design sollte der verdammte Altar eines jeden Programmierers sein. Und alles, was Sie "zwingt", das Richtige zu tun oder Sie vor sich selbst zu schützen, sollte mit dem gleichen Misstrauen betrachtet werden, das Flaschen Schlangenöl vorbehalten ist, IMO. Schlangenöl in der modernen IT und allgemeinen Entwicklung wird, wenn Sie es noch nicht wissen, in flüssiger Form verkauft.

Erik Reppen
quelle
1
Ich schreibe viele Unit-Tests. Ich werde keinen Code ohne sie schreiben. Aber ich stimme Ihren Ansichten zu. Die Tests sollten die Entwicklung leiten und nicht vorantreiben . Sie können das sorgfältige Nachdenken über ein Problem nicht automatisieren.
FizzyTea
Ich habe kein Problem mit automatisierten Tests. Aber zu jeder Zeit scheint mir eine großangelegte Übernahme eher eine Panik als ein Prozess zu sein. Ich bevorzuge es, diese Zeit für das Design und die Automatisierung von Tests und Validierungen an Punkten zu sparen, an denen Sie wahrscheinlich mit einer Vielzahl von Dingen interagieren, die Sie nicht kontrollieren können.
Erik Reppen
5

Nach meiner Erfahrung sind Unit-Tests in der Tat sehr nützlich, wenn Sie mit ihnen beginnen und bei ihnen bleiben, z. B. testgetriebene Entwicklung. Hier ist der Grund:

  • Unit-Tests zwingen Sie, darüber nachzudenken, was Sie wollen und wie Sie sicherstellen können, dass Sie es haben, bevor Sie den Code schreiben, der es tut . In einem TDD-Szenario schreiben Sie zuerst den Test. Sie müssen daher wissen, was der Code, den Sie schreiben möchten, tun muss und wie Sie überprüfen können, ob dies erfolgreich war, um einen "roten" Test zu schreiben, den Sie dann durch Schreiben des Codes auf "grün" setzen weitergeben. In vielen Fällen werden Sie gezwungen, sich ein wenig mehr Gedanken über den Algorithmus zu machen, den Sie schreiben möchten, um diesen Test zu bestehen. Dies ist immer eine gute Sache, da hierdurch Logikfehler und "Eckfälle" reduziert werden. Während Sie den Test schreiben, überlegen Sie, wie dies fehlschlagen könnte und was ich hier nicht teste, was zu einem robusteren Algorithmus führt.

  • Unit-Tests zwingen Sie zu überlegen, wie der Code, den Sie schreiben möchten, verbraucht wird . Bevor ich TDD lernte, gab es VIELE Male, in denen ich Code schrieb, der erwartete, dass eine Abhängigkeit in eine Richtung funktioniert, und dann eine Abhängigkeit erhielt, die von einem Kollegen geschrieben wurde, der auf eine völlig andere Weise arbeitete. Während dies mit TDD immer noch möglich ist, müssen Sie beim Komponententest überlegen, wie Sie das von Ihnen geschriebene Objekt verwenden möchten, da dies ein Beispiel für die Verwendung des Objekts ist. Sie werden das Objekt dann hoffentlich so schreiben, dass es leicht zu konsumieren und gegebenenfalls anzupassen ist (obwohl das Programmieren auf vordefinierte Schnittstellen eine bessere Gesamtlösung für dieses Problem darstellt, für das kein TDD erforderlich ist).

  • Unit-Tests ermöglichen es Ihnen, "Code durch Testen" . Ein Refactoring-Tool wie ReSharper kann Ihr bester Freund sein, wenn Sie es zulassen. Sie können es verwenden, um das Grundgerüst neuer Funktionen zu definieren, während Sie die Verwendung in einem Test definieren.

    Angenommen, Sie müssen ein neues Objekt MyClass erstellen. Sie erstellen zunächst eine Instanz von MyClass. "MyClass gibt es aber nicht!", Beschwert sich ReSharper. "Dann erstelle es" sagst du mit einem Druck von Alt + Enter. Und schon haben Sie Ihre Klassendefinition. In der nächsten Zeile des Testcodes rufen Sie eine Methode MyMethod auf. "Das gibt es aber nicht!", Sagt ReSharper. "Dann erstelle es", wiederholst du mit einem weiteren Alt + Enter. Sie haben mit wenigen Tastendrücken das "Gerüst" Ihres neuen Codes definiert. Während Sie die Verwendung weiter ausarbeiten, werden Sie von der IDE informiert, wenn etwas nicht passt. In der Regel ist die Lösung so einfach, dass die IDE oder ein in sie integriertes Tool weiß, wie es behoben werden kann.

    Extremere Beispiele entsprechen dem "Triple-A" -Modell; "Arrangieren, handeln, behaupten". Richten Sie alles ein, führen Sie die eigentliche Logik aus, die Sie testen, und bestätigen Sie dann, dass die Logik korrekt ist. Bei dieser Codierung ist es sehr natürlich, die Lösung in den Test zu codieren. Mit ein paar Tastendrücken können Sie diese Logik extrahieren und an einer Stelle platzieren, an der sie im Produktionscode verwendet werden kann. Anschließend können Sie kleine Änderungen am Test vornehmen, die sie auf die neue Position der Logik verweisen. Wenn Sie dies auf diese Weise tun, müssen Sie den Code modular und einfach wiederverwenden, da die zu testenden Einheiten weiterhin zugänglich sein müssen.

  • Unit-Tests laufen um viele Größenordnungen schneller als jeder manuelle Test, den Sie sich vorstellen können. Es gibt einen Punkt, der bei größeren Projekten sehr schnell erreicht wird und bei dem sich der Zeitaufwand für Komponententests durch die Reduzierung des manuellen Testaufwands amortisiert. Sie müssen IMMER den Code ausführen, den Sie gerade geschrieben haben. Traditionell haben Sie dies manuell getan, indem Sie ein großes Programm gestartet, durch die Benutzeroberfläche navigiert, um die Situation einzurichten, für die Sie das Verhalten geändert haben, und anschließend die Ergebnisse erneut über die Benutzeroberfläche oder in Form von Daten überprüft haben. Wenn der Code TDDed war, führen Sie einfach die Komponententests durch. Ich garantiere Ihnen, wenn Sie gute Unit-Tests schreiben, ist die letztere Option um ein Vielfaches schneller als die erstere.

  • Unit-Tests erfassen Regression . Wieder gab es viele Male, bevor ich TDD lernte, wo ich hineinging, was ich für eine chirurgische Änderung an einem Teil des Codes hielt, und verifizierte, dass die Änderung ein fehlerhaftes Verhalten (oder ein neues gewünschtes Verhalten) in der berichteten Situation feststellte , und überprüfte es für die Freigabe, nur um festzustellen, dass die Änderung einen anderen Eckfall in einem völlig anderen Modul durchbrach, das zufällig denselben Codeblock wiederverwendete. In einem TDDed-Projekt kann ich einen Test schreiben, in dem überprüft wird, ob eine Änderung vorgenommen wird, die Änderung vorgenommen wird und dann die gesamte Suite ausgeführt wird. Wenn alle anderen Verwendungen des Codes TDDed waren und meine Änderung etwas brachte, werden die Tests für diese durchgeführt andere Dinge werden scheitern und ich kann nachforschen.

    Wenn Entwickler alle Codezeilen, die von einer möglichen Änderung betroffen sein könnten, manuell suchen und testen müssten, würde niemals etwas unternommen, da die Kosten für die Ermittlung der Auswirkungen einer Änderung die Änderung unmöglich machen würden. Zumindest wäre nichts FEST und daher leicht zu warten, da Sie es niemals wagen würden, etwas zu berühren, das an mehreren Stellen verwendet werden könnte. Sie würden stattdessen Ihre eigene, sehr ähnliche Lösung entwickeln, die jedoch Ihre geringfügigen Änderungen einbezieht. Dies verstößt gegen SRP und möglicherweise gegen OCP und verwandelt Ihre Codebasis langsam in einen Patchwork-Quilt.

  • Unit-Tests formen die Architektur auf typisch vorteilhafte Weise . Unit-Tests sind Tests, die isoliert von jeder anderen Logik durchgeführt werden. Um in der Lage zu sein, Ihren Code zu testen, müssen Sie den Code so schreiben, dass Sie könnenisoliere es. Gute Entwurfsentscheidungen wie lose Kopplung und Abhängigkeitsinjektion werden somit natürlich aus dem TDD-Prozess herausgerissen. Abhängigkeiten müssen injiziert werden, damit Sie in einem Test einen "Mock" oder "Stub" injizieren können, der die Eingabe erzeugt oder die Ausgabe für die zu testende Situation verarbeitet, ohne "Nebenwirkungen" zu verursachen. Die "Usage First" -Mentalität von TDD führt im Allgemeinen zu "Codierung an Schnittstellen", dem Wesen der losen Kopplung. Mit diesen guten Konstruktionsprinzipien können Sie Änderungen in der Produktion vornehmen, z. B. das Ersetzen einer ganzen Klasse, ohne dass große Mengen der Codebasis zur Anpassung geändert werden müssen.

  • Unit-Tests zeigen, dass der Code funktioniert, anstatt zu beweisen , dass der Code funktioniert . Auf den ersten Blick könnte man das für einen Nachteil halten; Ist der Beweis doch besser als die Demonstration? Theorie ist großartig; Computer- und algorithmische Theorie ist die Grundlage unserer Arbeit. Ein mathematischer Beweis für die Richtigkeit eines Algorithmus ist jedoch kein Beweis für die Richtigkeit der Implementierung . Ein mathematischer Beweis zeigt nur , dass Code für den Algorithmus haften sollte korrekt sein. Ein Unit - Test zeigt , dass der Code geschrieben tatsächlich tut , was Sie dachten , es tun würde, und somit Hinweise darauf es ist richtig. Dies ist in der Regel von viel größerem Wert als ein theoretischer Beweis.

Nun, alles in allem gibt es Nachteile bei Unit-Tests:

  • Sie können nicht alles in einem Unit-Test testen. Sie können Ihr System so planen, dass die Anzahl der LOCs, die nicht durch einen Komponententest abgedeckt werden, minimiert wird. Es gibt jedoch ganz einfach bestimmte Bereiche des Systems, die nicht durch Komponententests überprüft werden können. Ihre Datenzugriffsebene kann verspottet werden, wenn sie von anderem Code verwendet wird. Die Datenzugriffsebene selbst enthält jedoch eine Reihe von Nebenwirkungen, und es ist in der Regel nicht möglich, einen Großteil (die meisten?) Eines Repositorys oder DAO zu testen. In ähnlicher Weise sind in Code, der Dateien verwendet, Netzwerkverbindungen herstellt usw., Nebenwirkungen eingebaut, und Sie können die Codezeile, die dies bewirkt, einfach nicht einem Unit-Test unterziehen. UI-Elemente können oft nicht Unit-getestet werden. Sie können Codebehind-Methoden wie Ereignishandler testen, Sie können Testkonstruktoren einbinden und überprüfen, ob Handler angeschlossen sind. Es gibt jedoch keinen In-Code-Ersatz für einen Benutzer, der mit der Maus auf ein bestimmtes grafisches Element klickt und beobachtet, wie der Handler aufgerufen wird. Das Erreichen dieser Grenzen zwischen dem, was in der Einheit angemessen getestet werden kann und was nicht, wird als "Abschaben des Randes des Sandkastens" bezeichnet. Darüber hinaus können Sie nur noch Integrationstests, automatische Abnahmetests und manuelle Tests verwenden, um das Verhalten zu überprüfen.

  • Viele Vorteile von Komponententests kommen ohne TDD nicht zum Tragen. Es ist durchaus möglich, Code zu schreiben und dann Tests zu schreiben, die den Code ausführen. Sie sind immer noch "Komponententests". Wenn Sie jedoch zuerst Code schreiben, verlieren Sie viele der Vorteile, die der "Test-First" -Entwicklung inhärent sind: Code ist nicht unbedingt so aufgebaut, dass er einfach getestet oder sogar in der Produktion verwendet werden kann ; Sie erhalten nicht den "Double-Check" -Denkprozess, der dem Schreiben des Tests und dem Nachdenken über das innewohnt, worüber Sie nicht nachgedacht haben. Sie codieren nicht durch Testen. Und wenn Sie Code schreiben, ihn manuell testen und sehen, dass er funktioniert, dann codieren Sie einen fehlgeschlagenen Komponententest. Was ist falsch, der Code oder der Test? Ihre Hauptvorteile sind die Verhinderung von Regressionen (Sie werden benachrichtigt, wenn Code, der zuvor die Tests bestanden hat, fehlschlägt) und die Hochgeschwindigkeitsüberprüfung im Vergleich zu manuellen Tests. Der Verlust von TDD '

  • Unit-Tests verursachen einen Mehraufwand . Ganz einfach, Sie schreiben Code, um den Code zu testen, den Sie schreiben. Dies erhöht notwendigerweise den Gesamt-LOC eines Entwicklungsprojekts, und ja, der LOC für Tests kann den LOC für das tatsächliche Projekt überschreiten. Naive Entwickler und Nicht-Entwickler werden sich mit diesem Sachverhalt befassen und sagen, dass die Tests Zeitverschwendung sind.

  • Unit Testing erfordert Disziplin. Sie müssen Tests schreiben, die die Codebasis angemessen ausüben (gute Codeabdeckung), Sie müssen sie regelmäßig ausführen (wie bei jeder Änderung, wenn die vollständige Suite ausgeführt werden soll) und Sie müssen alles "grün" halten ( alle Tests bestehen). Wenn Probleme auftreten, müssen Sie sie entweder beheben, indem Sie den Code korrigieren, der die Erwartungen nicht erfüllt, oder indem Sie die Erwartungen der Tests aktualisieren. Wenn Sie die Tests ändern, sollten Sie nach dem Warum fragen und genau auf sich selbst achten. Es ist unglaublich verlockend, fehlerhafte Aussagen einfach an das aktuelle Verhalten anzupassen oder fehlerhafte Tests einfach zu entfernen. Diese Tests sollten jedoch auf Anforderungen basieren, und wenn die beiden nicht übereinstimmen, haben Sie ein Problem. Wenn diese Dinge nicht erledigt sind,

  • Unit-Tests erfordern mehr Ausrüstung. Die übliche Lösung für das oben genannte Bedürfnis nach Disziplin und die natürliche Tendenz des Menschen, faul und gelassen zu werden, ist ein "Build-Bot", auf dem ein Softwarepaket "Continuous Integration" wie TeamCity, CruiseControl usw. ausgeführt wird, das Komponententests durchführt Codeabdeckungsmetriken und andere Steuerelemente wie "Triple-C" (Einhaltung der Codierungskonvention, a la FxCop). Die Hardware für den Build-Bot muss ausreichend leistungsfähig sein (andernfalls entspricht sie nicht der Rate der Code-Check-Ins, die das durchschnittliche Team durchführt), und die Check-In-Prozeduren für den Bot müssen auf dem neuesten Stand gehalten werden (sofern zutreffend) Es wird eine neue Bibliothek mit Komponententests erstellt. Build-Skripte, mit denen Komponententests ausgeführt werden, müssen geändert werden, damit sie in dieser Bibliothek angezeigt werden. Das ist weniger Arbeit als es klingt, In der Regel ist jedoch ein gewisses technisches Fachwissen von mindestens einigen Mitarbeitern im Team erforderlich, die wissen, wie der Kern der verschiedenen Erstellungsprozesse funktioniert (und sie daher in Skripten automatisieren und diese Skripten warten können). Es erfordert auch noch Disziplin in Form von Aufmerksamkeit, wenn der Build "abbricht", und das Korrigieren dessen, was den Abbruch des Builds (korrekt) verursacht hat, bevor etwas Neues eingecheckt wird.

  • Unit-Tests können dazu führen, dass Code auf nicht ideale Weise archiviert wird . Während TDD in der Regel für die Modularität und Wiederverwendbarkeit von Code gut ist, kann es sich nachteilig auf die ordnungsgemäße Zugänglichkeit von Code auswirken. Objekte und Elemente, die in Produktionsbibliotheken abgelegt sind, können nicht privat oder intern sein, wenn sie direkt von Komponententests verwendet werden. Dies kann zu Problemen führen, wenn andere Programmierer, die jetzt ein Objekt sehen, versuchen, es zu verwenden, wenn sie stattdessen etwas anderes in der Bibliothek vorhandenes verwenden sollen. Code-Überprüfungen können dabei hilfreich sein, können jedoch Anlass zur Sorge geben.

  • Unit-Tests verbieten im Allgemeinen Codierungsstile für "schnelle Anwendungsentwicklung". Wenn Sie Komponententests schreiben, codieren Sie nicht "schnell und locker". Das ist in der Regel eine gute Sache, aber wenn Sie sich unter einer Frist befinden, die außerhalb Ihrer Kontrolle liegt, oder wenn Sie eine Änderung mit sehr geringem Umfang durchführen und der Stakeholder (oder Ihr Chef) sich fragt, warum all das nur passieren muss Wenn Sie eine Codezeile ändern, kann es einfach unmöglich sein, die richtige Unit-Testsuite zu schreiben und zu warten. Agile Prozesse helfen in der Regel dabei, indem sie den Entwicklern ein Mitspracherecht bei den Zeitanforderungen einräumen. Denken Sie daran, der Verkäufer muss nur "Ja, können wir" sagen und erhält die Provisionsüberprüfung, es sei denn, die Mitarbeiter, die die Arbeit tatsächlich ausführen müssen, sagen "Nein, können wir nicht" und werden aufmerksam beobachtet. Aber nicht jeder ist agil und agil hat seine eigenen Grenzen.

KeithS
quelle
4

Komponententests sind nützlich, wenn sie richtig angewendet werden. Es gibt verschiedene Probleme mit Ihrer Logik.

"Wenn ich mich entwickle, mache ich eine Menge Trial-and-Error durch", sagte Kevin.

Schauen Sie sich die Programmierung zufällig an. Es ist besser zu verstehen, was ein Code tun soll, und dann zu beweisen, dass er dies durch einen Unit-Test tut. Nehmen Sie nicht an, dass ein Code einfach funktioniert, weil die Benutzeroberfläche beim Ausführen des Programms nicht beschädigt wurde!

s writing unit tests for ASP.NET web forms something that is done often

Ich kenne keine statistischen Daten, um zu sagen, wie oft Leute Webformulare testen. Das ist egal. Die Benutzeroberfläche ist schwer zu testen und Unit Tests sollten auch nicht an eine Benutzeroberfläche gekoppelt werden. Teilen Sie Ihre Logik in Ebenen, Klassenbibliotheken, die getestet werden können. Testen Sie die Benutzeroberfläche separat von der Back-End-Logik.

So, question number 2: Would you guys advise me to start writing unit tests?

Ja. Sobald Sie sich an sie gewöhnt haben, beschleunigen sie Sie. Die Wartung ist weitaus zeit- und kostenintensiver als die anfängliche Entwicklungsphase. Die Wartung wird bei Komponententests erheblich unterstützt, selbst bei Ersttests und Fehlerbehebungen.

P. Brian Mackey
quelle
Es gibt Test-Frameworks, die Tests auf aspx-Seiten durchführen können, um einfach zu testen, ob die Seiten in verschiedenen Szenarien erfolgreich geladen wurden oder nicht. Das ist vielleicht nicht gut genug, aber es ist besser als nichts.
Ehrfurcht
4

Auf praktischer Ebene können Unit-Tests aus einem sehr wichtigen Grund äußerst nützlich sein: Sie können jeweils ein Bit eines Codes testen.

Wenn Sie eine ganze Abfolge komplexer Schritte schreiben und diese am Ende debuggen, finden Sie in der Regel viele Fehler, und der Prozess ist im Allgemeinen schwieriger, da Sie im weiteren Verlauf des Prozesses sind. In Visual Studio können Sie einen Schnelltest generieren, ihn ein wenig ändern und NUR diesen Test ausführen . Sie wissen dann, dass sich beispielsweise eine Methode, die diese Methode aufruft, darauf verlassen kann. So erhöht sich das Vertrauen.

Unit-Tests beweisen nicht, dass Ihr Programm korrekt ist! : Unit-Tests prüfen auf Regressionen in vertraulichem Code und ermöglichen es Ihnen, neue Methoden zu testen, die Sie schreiben.

Unit-Tests sind nicht zum Testen von Frontends gedacht : Stellen Sie sich einen Unit-Test als das kleine Projekt vor, das Sie erstellen, um eine neue Methode zu testen, die Sie schreiben, oder etwas anderes, und nicht als eine Bedingung, die Ihr Code erfüllen muss.

Unit-Tests eignen sich hervorragend für kollaborative Umgebungen : Wenn ich einem Kollegen eine Methode zur Verfügung stellen muss, die eine völlig andere Technologie verwendet als ich, wie er sie zum Beispiel von iOS aus anruft, kann ich schnell einen Unit-Test schreiben, um festzustellen, ob die Methode, die er möchte a) Führt die korrekten Daten erneut aus. b) Führt gemäß seinen Spezifikationen aus.

Tjaart
quelle
"Unit Tests sind nicht zum Testen von Frontends gedacht" Wer sagt das? Ich frage es nicht. Ich möchte es nur wissen, weil viele Leute die falsche Idee zu haben scheinen und ich möchte sie mit dem Stick schlagen, der nicht das ist, was diese einflussreiche Quelle für TDD-Befürworter ist.
Erik Reppen
Einige Leute, ich selbst eingeschlossen, hatten dieses Missverständnis, als sie zum ersten Mal auf Unit-Tests stießen, also kläre ich das gerade auf. Ich weiß nicht, warum Sie das Gefühl haben, ich fordere Sie heraus, in der Tat stimme ich Ihnen voll und ganz zu.
Tjaart
4

Eine Sache, die nicht berührt zu werden scheint, ist die Komplexität des Testens verschiedener Codetypen.

Wenn Sie mit einfachen Ein- und Ausgaben zu tun haben, ist es im Allgemeinen einfach, einen Komponententest durchzuführen, und wenn die Tests unter Berücksichtigung der Randbedingungen des zu testenden Codes ausgewählt werden, können Sie sicher sein, dass sie richtig sind. Es wäre verrückt, keine Tests für einen solchen Code zu schreiben. (Beachten Sie, dass der meiste Code, der in Bibliotheken abgelegt wird, diese Kriterien erfüllt.)

In anderen Fällen müssen Sie jedoch riesige Mocks erstellen, um zu testen, weil der Code mit komplexen zugrunde liegenden Daten spielt (normalerweise eine Datenbank, muss es aber nicht sein) oder sehr komplexe Ausgabedaten erzeugt (denken Sie an eine Routine, die sich dreht) Ein Startwert in ein Spiellevel (für ein ziemlich extremes Beispiel) und Unit-Tests sind bei weitem nicht so nützlich. Alles in Ihren Testfällen abzudecken ist normalerweise ein Wunschtraum, und wenn Sie einen Fehler finden, ist es fast immer ein Fall, an den Sie nie gedacht haben und für den Sie ohnehin keinen Test hätten erstellen können.

Es gibt keine Silberkugeln, alles, was als Silberkugel dargestellt wird, ist bei weitem nicht so gut, wie die Befürworter behaupten, aber das heißt nicht, dass es nutzlos ist.

Loren Pechtel
quelle
4

Das Schreiben von Komponententests für ASP.NET-Webformularanwendungen ist NICHT üblich und sehr schwierig. Dies bedeutet jedoch nicht, dass das Projekt es überspringen sollte.

Unit-Tests sind corner stonesfür unternehmenskritische Anwendungen gedacht und bieten Zuverlässigkeit und Sicherheit, dass die Kernfunktionalität wie erwartet funktioniert.

Mit einem ASP.NET MVP-Muster , das für die Entwicklung von Webformularen verwendet werden kann, können Sie Unit-Tests möglicherweise viel einfacher einführen . Es wird die Trennung von Bedenken und Bedenken einführen ability to write essential unit tests.

Einige Referenzen, die hilfreich sein könnten, sind:

ElYusubov
quelle
2
+1 Es spielt keine Rolle, ob Sie Unit-Tests durchführen oder nicht, MVP ist der richtige Weg, wenn Sie mit Web Forms arbeiten (möglicherweise auch mit WinForms).
Simoraman
3

Mit Unit-Tests können Sie Ihren Code sicher ändern (Refactoring, Verbesserung usw.), ohne befürchten zu müssen, dass Sie etwas im System beschädigen könnten. Dies erweist sich für große Anwendungen als sehr nützlich, wenn Sie nicht wirklich alle Auswirkungen Ihrer Codeänderung kennen (trotz loser Kopplung).

m3th0dman
quelle
6
Ohne Angst ist ein falsches Sicherheitsgefühl.
Coder
Vielleicht ist "weniger Angst" ein besserer Ausdruck, aber die Antwort ist immer noch weitgehend richtig.
Brendan Long
1
@Coder Wenn Ihre Tests nach dem Refactoring erfolgreich sind, können Sie ziemlich sicher sein, dass Ihre Code-Verbesserung das Verhalten der Anwendung nicht verändert hat (grob gesagt, Sie haben keine neuen Fehler eingeführt, aber dies ist nicht unbedingt der Fall, weil Sie dies nicht erreichen können 100% Testabdeckung).
m3th0dman
2

Es ist meine Erfahrung , dass ja , Unit - Tests nützlich sind.

Beim Unit Testing geht es darum, Teile des Codes, den Sie schreiben, zu trennen und sicherzustellen, dass sie isoliert funktionieren. Diese Isolation kann in der Tat das Erstellen von gefälschten oder nachgemachten Objekten beinhalten, um mit dem Objekt zu sprechen, das Sie testen, oder auch nicht. Es hängt sehr stark von der Architektur Ihres Objekts ab.

Unit Testing bietet verschiedene Vorteile:

Dies stellt in erster Linie sicher, dass die von Ihnen getesteten Einheiten so funktionieren, wie Sie als Entwickler glauben, dass sie funktionieren sollten. Dies ist zwar weniger als es sich anhört: Es muss nicht unbedingt heißen, dass das Objekt korrekt funktioniert. Nur dass es so funktioniert, wie Sie denken, dass es funktionieren sollte, ist es eine weitaus stärkere Aussage als die Trial-and-Error-Methode, die ohne Unit-Tests erforderlich ist.

Darüber hinaus gewährleistet es , dass Einheiten , die die Art und Weise weiter arbeiten Sie, der Entwickler, dachten sie sollen arbeiten. Softwareänderungen, die sich auf unerwartete Weise auf Geräte auswirken können.

Ein weiterer Nebeneffekt ist , dass es bedeutet , dass die Einheiten , die Sie testen tun Arbeit in Isolation. Dies bedeutet im Allgemeinen, dass Sie nicht mehr auf konkrete Klassen, sondern auf Schnittstellen programmieren, um die Kopplung zu verringern und die Kohäsion zu erhöhen. Ja: nur Ihre Einheiten von Code ermöglicht haben Unit - Tests werden natürlich das Design Ihres Codes verbessern.

Jedoch...

Unit Testing ist nicht das Ende des Testens. Andere Arten von Tests sind noch erforderlich. Selbst wenn Sie beispielsweise gezeigt haben, dass Einheiten so funktionieren, wie Sie es erwarten, müssen Sie dennoch zeigen, dass jede Einheit so funktioniert, wie die Einheiten, die mit ihr sprechen, es erwarten, dass es funktioniert. Das heißt, integrieren sich Ihre Komponenten richtig ineinander?

Kaz Dragon
quelle
1

Für einfache Apps mit einer geringen Anzahl zu testender Ebenen (Hauptfenster -> Untermenü) ist das Kompilieren zur Überprüfung der Änderungen möglicherweise in Ordnung.

Bei größeren Apps, bei denen die Navigation in 30 Sekunden dauert, um die zu testende Seite zu finden, ist dies sehr teuer.

DefenestrationDay
quelle
1

Ich möchte dem eine neue Seite hinzufügen (eigentlich eine ziemlich alte): Unit-Tests sind nicht so nützlich, wenn Ihr Code gut gestaltet ist .

Ich weiß, dass die meisten Programmierer kein Programmdesign mehr machen, und ich fand, dass Komponententests eine ziemlich zeitaufwendige Notwendigkeit sind, um in eine TDD-Kultur zu passen, aber bisher habe ich nur 1-2 Moll getroffen Fehler pro tausend Testzeilen meines Codes - nicht nur das, was ich geschrieben habe, sondern auch das, was offizielle Tester geschrieben haben.

Ich nehme an, Sie werden auch kein Programmdesign mehr machen - die heutigen Leute werden Sie unter Druck setzen, es nicht zu machen -, aber vielleicht ist es wert, daran zu denken, dass der Komponententest im Vergleich zum Design eine sehr, sehr niedrige Effizienzmethode ist.

Dies ist ein dijsktraian Argument: Unit-Test kann nur für ein Programm ausgeführt werden, das detailliert genug ist, um ausgeführt zu werden.

Wenn Sie vor dem eigentlichen Schreiben Flussdiagramme / Zustands- / Aktionsdiagramme, Sequenzdiagramme, Objektinventare (und zuletzt UND-Klassendiagramme) für Ihren Code zeichnen, können Sie die meisten potenziell bedrohlichen Fehler beseitigen, indem Sie einfach herumspüren Ihre Zeilen und überprüfen Sie Ihre Namen.

Heutzutage werden Klassendiagramme aus Code generiert, der Hunderte, manchmal Tausende von Klassen enthält und völlig unbrauchbar ist - alles, was mehr als 15 Elemente enthält, ist für den Menschen unerkennbar.

Sie müssen wissen, welche 10 + -5 Klassen wichtig sind oder was Sie gerade tun, und Sie müssen in der Lage sein, Ihren Code aus mehreren Blickwinkeln zu überprüfen, wobei jedes Diagramm GENAU die Blickwinkel darstellt, die Sie betrachten, und Sie müssen Tausende von Fehlern beseitigen auf Papier.

  • Einchecken eines dynamischen Codes, um festzustellen, ob Typen erfüllt sind (indem einfach die Eingabe- / Ausgabetypen in einem Flussdiagramm angezeigt und mit einem Bleistift oder einer anderen Farbe verbunden werden),
  • Prüfen, ob alle Zustände behandelt werden (indem Sie die Vollständigkeit Ihrer Zustände prüfen),
  • Verfolgen der Linien, um sicherzustellen, dass alles ein Ende findet (jedes Flussdiagramm sollte für mathematisch denkende ein vollständig definierter deterministischer Automat mit endlichen Zuständen sein)
  • Sicherstellen, dass bestimmte Komponenten nichts miteinander zu tun haben (indem alle Abhängigkeiten extrahiert werden) (gut für die Sicherheit)
  • Vereinfachung des Codes durch Konvertieren von Abhängigkeiten in Assoziationen (Abhängigkeiten stammen von den Klassen, die die Membermethoden verwenden)
  • Namen überprüfen, nach gemeinsamen Präfixen suchen, Synonyme löschen usw.

es gibt einfach so viel einfacher ...

Außerdem fand ich heraus, dass meine Anwendungen benutzerfreundlicher sind, wenn sie direkt aus Anwendungsfällen stammen ... wenn die Anwendungsfälle gut geschrieben sind (ACTOR-Verb Betreff, Maintainer fordert zum Öffnen des Geldautomaten auf) ... Das

Ich habe mit 95 +% der Codeabdeckungen codiert. Natürlich mache ich manchmal Unit-Tests, insb. für Grenzkontrollen in Berechnungen, aber ich muss noch ernsthafte Regressionen einhalten (ernst: wird nicht in 24 Stunden ausgelöscht), weil ich Unit-Tests nicht einmal für Refactorings verwendet habe.

Manchmal mache ich 3-4 Tage lang keine einzige Codezeile, sondern zeichne nur. Dann tippe ich an einem Tag 1500-2000 Zeilen ein. Am nächsten Tag sind sie größtenteils produktionsbereit. Manchmal werden Komponententests geschrieben (mit 80 +% der Abdeckung), manchmal (zusätzlich) werden Tester gebeten, zu versuchen, sie zu brechen, und jedes Mal werden einige Personen gebeten, sie durch Anschauen zu überprüfen.

Ich muss noch sehen, dass diese Unit-Tests irgendetwas finden.

Ich wünschte, Design-Thinking würde TDD ersetzen ... aber TDD ist so viel einfacher, als würde man mit einem Vorschlaghammer arbeiten ... man muss nachdenken, und die meiste Zeit bleibt man auf der Tastatur.

Aadaam
quelle
Ich denke, Sie können an der Tastatur entwerfen. Das Planen und Organisieren von Code erfordert jedoch viel mehr Gedanken als nur das Stolpern durch Eingabe und Ausgabe in Klassen, bei denen es sich ebenfalls um monolithische Funktionen handeln kann.
Erik Reppen
Vertrauen Sie mir, monolithische Funktionen passen nicht auf A4-Papier (oder US-Letter). Manchmal, wenn ich faul bin, mache ich "Design" auf der Tastatur, aber das ist nicht die gleiche Qualität. Wenn ich ernsthaft entwickle, entwerfe ich mit UML. Wenn Sie diese zeichnen, versuchen Sie, sich und anderen auf eine sehr eingeschränkte, aber dennoch strukturierte Weise zu erklären, was passiert, und wenn Sie in der Lage sind, den Code aus jeder einzelnen Perspektive zu erklären, geben Sie nur dann etwas ein es in, und plötzlich alle Ihre Fehler sind höchstens Tippfehler ...
Aadaam