Ich habe festgestellt, dass es in C # .NET nur drei Möglichkeiten zum Testen von Einheiten (Mock / Stub) gibt:
Angesichts der Tatsache, dass zwei davon nicht kostenlos sind und einer Release 1.0 noch nicht erreicht hat, ist es nicht einfach, statische Inhalte zu verspotten.
Macht das statische Methoden und solche "bösen" (im Sinne von Unit-Tests)? Und wenn ja, warum möchte Resharper, dass ich alles herstelle, was statisch oder statisch sein kann? (Vorausgesetzt, Resharper ist nicht auch "böse".)
Erläuterung: Ich spreche von dem Szenario, in dem Sie eine Methode einem Komponententest unterziehen möchten und diese Methode eine statische Methode in einer anderen Einheit / Klasse aufruft . Wenn Sie nach den meisten Definitionen des Komponententests die getestete Methode nur die statische Methode in der anderen Einheit / Klasse aufrufen lassen, dann sind Sie kein Komponententest, sondern ein Integrationstest . (Nützlich, aber kein Komponententest.)
quelle
Antworten:
Wenn ich mir die anderen Antworten hier anschaue, kann es zu Verwirrungen kommen zwischen statischen Methoden, die einen statischen Zustand aufweisen oder Nebenwirkungen verursachen (was für mich nach einer wirklich schlechten Idee klingt), und statischen Methoden, die lediglich einen Wert zurückgeben.
Statische Methoden, die keinen Zustand haben und keine Nebenwirkungen hervorrufen, sollten leicht in der Einheit testbar sein. Tatsächlich betrachte ich solche Methoden als eine "arme" Form der funktionalen Programmierung; Sie übergeben der Methode ein Objekt oder einen Wert und sie gibt ein Objekt oder einen Wert zurück. Nichts mehr. Ich verstehe nicht, wie sich solche Methoden überhaupt negativ auf das Testen von Einheiten auswirken würden.
quelle
Sie scheinen statische Daten und statische Methoden zu verwechseln . Wenn ich mich recht erinnere, empfiehlt Resharper,
private
Methoden innerhalb einer Klasse statisch zu machen, wenn dies möglich ist. Ich glaube, dies bringt einen kleinen Leistungsvorteil. Es wird nicht empfohlen, "alles, was sein kann", statisch zu machen!An statischen Methoden ist nichts auszusetzen, und sie sind einfach zu testen (solange sie keine statischen Daten ändern). Stellen Sie sich zum Beispiel eine Mathematikbibliothek vor, die sich gut für eine statische Klasse mit statischen Methoden eignet. Wenn Sie eine (erfundene) Methode wie diese haben:
dann ist dies hervorragend testbar und hat keine Nebenwirkungen. Sie müssen nur überprüfen, ob Sie nach dem Eintreffen von beispielsweise 20 400 zurückerhalten. Kein Problem.
quelle
System.Math
), ganz zu schweigen von der Fülle der statischen Factory-Methoden usw. Außerdem könnten Sie niemals Erweiterungsmethoden usw. verwenden. Tatsache ist, dass dies einfache Funktionen sind grundlegend für moderne Sprachen. Sie können diese isoliert testen (da sie im Allgemeinen deterministisch sind) und sie dann problemlos in Ihren Klassen verwenden. Es ist kein Problem!Wenn die eigentliche Frage hier lautet: "Wie teste ich diesen Code?":
Dann überarbeiten Sie einfach den Code und fügen wie gewohnt den folgenden Aufruf an die statische Klasse ein:
quelle
Statik ist nicht unbedingt böse, aber sie kann Ihre Möglichkeiten einschränken, wenn es um Unit-Tests mit Fakes / Mocks / Stubs geht.
Es gibt zwei allgemeine Herangehensweisen an das Verspotten.
Die erste (traditionell von RhinoMocks, Moq, NMock2 implementierte; manuelle Mocks und Stubs sind auch in diesem Lager vorhanden) basiert auf Testnähten und Abhängigkeitsinjektion. Angenommen, Sie testen einen statischen Code in einer Einheit und er weist Abhängigkeiten auf. Was im Code geschieht oft so gestaltet ist , dass Statik ihre eigenen Abhängigkeiten schaffen, Invertierung Abhängigkeit Inversion . Sie werden schnell feststellen, dass Sie in den so gestalteten Testcode keine gespielten Schnittstellen einfügen können.
Die zweite (Mock-Funktion - implementiert von TypeMock, JustMock und Moles) basiert auf der .NET- Profiling-API . Es kann alle Ihre CIL-Anweisungen abfangen und einen Teil Ihres Codes durch eine Fälschung ersetzen. Dadurch können TypeMock und andere Produkte in diesem Camp alles verspotten: Statik, versiegelte Klassen, private Methoden - Dinge, die nicht testbar sind.
Es gibt eine anhaltende Debatte zwischen zwei Denkschulen. Man sagt, folgen Sie SOLID Prinzipien und Design für Testbarkeit (das beinhaltet oft schonende Statik). Der andere sagt, kaufe TypeMock und mach dir keine Sorgen.
quelle
Überprüfen Sie dies: "Statische Methoden sind der Tod für die Testbarkeit" . Kurze Zusammenfassung des Arguments:
Zum Komponententest müssen Sie einen kleinen Teil Ihres Codes nehmen, seine Abhängigkeiten neu verkabeln und ihn isoliert testen. Dies ist bei statischen Methoden schwierig, nicht nur, wenn sie auf den globalen Status zugreifen, sondern auch, wenn sie nur andere statische Methoden aufrufen.
quelle
Die einfache Wahrheit, die selten anerkannt wird, ist, dass eine Klasse, die eine vom Compiler sichtbare Abhängigkeit von einer anderen Klasse enthält, nicht isoliert von dieser Klasse getestet werden kann . Sie können etwas vortäuschen, das wie ein Test aussieht und in einem Bericht so angezeigt wird, als wäre es ein Test.
Der Schlüssel, der die Eigenschaften eines Tests definiert, ist jedoch nicht vorhanden. Scheitern, wenn Dinge falsch sind, vergehen, wenn sie richtig sind.
Dies gilt für alle statischen Aufrufe, Konstruktoraufrufe und Verweise auf Methoden oder Felder, die nicht von einer Basisklasse oder Schnittstelle geerbt wurden . Wenn der Klassenname im Code angezeigt wird, handelt es sich um eine vom Compiler sichtbare Abhängigkeit, ohne die Sie keine gültigen Tests durchführen können. Ein kleinerer Block ist einfach keine gültige prüfbare Einheit . Jeder Versuch, es so zu behandeln, als wäre es ein Ergebnis, das nicht aussagekräftiger ist, als ein kleines Hilfsprogramm zu schreiben, das das XML ausgibt, das von Ihrem Testframework verwendet wird, um zu sagen, dass der Test bestanden wurde.
Vor diesem Hintergrund gibt es drei Möglichkeiten:
Definieren Sie Unit-Tests als Tests der Unit, die aus einer Klasse und ihren fest codierten Abhängigkeiten besteht. Dies funktioniert, sofern Sie kreisförmige Abhängigkeiten vermeiden.
Erstellen Sie niemals Abhängigkeiten zur Kompilierungszeit zwischen Klassen, für die Sie verantwortlich sind. Dies funktioniert, vorausgesetzt, Sie haben nichts gegen den resultierenden Codestil.
Nicht Unit-Test, sondern Integrationstest. Was funktioniert, vorausgesetzt, es steht in keinem Konflikt mit etwas anderem, für das Sie den Begriff Integrationstest verwenden müssen.
quelle
Math.Pi
in einer Methode macht sie nach keiner vernünftigen Definition zu einem Integrationstest.Es gibt keine zwei Möglichkeiten. Die Vorschläge von ReSharper und einige nützliche Funktionen von C # würden nicht so häufig verwendet, wenn Sie isolierte Atom-Unit-Tests für Ihren gesamten Code schreiben würden.
Wenn Sie zum Beispiel über eine statische Methode verfügen und diese entfernen müssen, können Sie dies nur tun, wenn Sie ein profilbasiertes Isolationsframework verwenden. Eine aufrufkompatible Problemumgehung besteht darin, den oberen Rand der Methode so zu ändern, dass die Lambda-Notation verwendet wird. Zum Beispiel:
VOR:
NACH:
Die beiden sind anrufkompatibel. Anrufer müssen sich nicht ändern. Der Körper der Funktion bleibt der gleiche.
Dann können Sie in Ihrem Unit-Test-Code diesen Aufruf wie folgt stoppen (vorausgesetzt, er befindet sich in einer Klasse namens Database):
Ersetzen Sie es nach Beendigung des Vorgangs durch den ursprünglichen Wert. Sie können dies über einen try / finally-Befehl tun oder in Ihrer Unit-Test-Bereinigung den Code eingeben, der nach jedem Test aufgerufen wird:
Dadurch wird der statische Initialisierer Ihrer Klasse erneut aufgerufen.
Lambda-Funcs sind nicht so unterstützend wie normale statische Methoden, daher hat dieser Ansatz die folgenden unerwünschten Nebenwirkungen:
Nehmen wir jedoch an, Sie vermeiden die Statik vollständig und konvertieren sie in eine Instanzmethode. Es ist immer noch nicht verspottbar, es sei denn, die Methode ist entweder virtuell oder als Teil einer Schnittstelle implementiert.
In Wirklichkeit ist jeder, der die Lösung für das Stubben statischer Methoden vorschlägt, sie zu Instanzmethoden zu machen, auch gegen Instanzmethoden, die nicht virtuell oder Teil einer Schnittstelle sind.
Warum verfügt C # über statische Methoden? Warum sind nicht virtuelle Instanzmethoden zulässig?
Wenn Sie eine dieser "Funktionen" verwenden, können Sie einfach keine isolierten Methoden erstellen.
Also wann benutzt du sie?
Verwenden Sie sie für jeden Code, von dem Sie nicht erwarten, dass er jemals veröffentlicht werden soll. Einige Beispiele: Die Format () -Methode der String-Klasse Die WriteLine () -Methode der Console-Klasse Die Cosh () -Methode der Math-Klasse
Und noch etwas. Die meisten Leute interessieren sich nicht dafür, aber wenn Sie die Leistung eines indirekten Aufrufs beurteilen können, ist dies ein weiterer Grund, Instanzmethoden zu vermeiden. Es gibt Fälle, in denen die Leistung beeinträchtigt wird. Deshalb gibt es in erster Linie nicht-virtuelle Methoden.
quelle
R # ist nicht das einzige Tool, das diesen Vorschlag macht. Die FxCop / MS-Code-Analyse macht dasselbe.
Ich würde allgemein sagen, dass wenn die Methode statisch ist, sie im Allgemeinen auch testbar sein sollte. Das bringt einige Überlegungen zum Design und wahrscheinlich mehr Diskussionen mit sich, als ich gerade in meinen Fingern habe. Warten Sie also geduldig auf die Abstimmungen und Kommentare ...;)
quelle
Ich sehe, dass nach langer Zeit noch niemand eine wirklich einfache Tatsache festgestellt hat. Wenn der Resharper mir sagt, dass ich eine Methode statisch machen kann, bedeutet das eine große Sache für mich. Ich kann seine Stimme sagen: "Hey, Sie, diese logischen Teile sind nicht die VERANTWORTUNG der aktuellen Klasse, also sollte sie draußen bleiben in irgendeiner Helferklasse oder so ".
quelle
Wenn die statische Methode von einer anderen Methode aus aufgerufen wird , ist es nicht möglich, einen solchen Aufruf zu verhindern oder zu ersetzen. Dies bedeutet, dass diese beiden Methoden eine einzige Einheit bilden. Unit-Test jeder Art testet sie beide.
Und wenn diese statische Methode mit dem Internet kommuniziert, Datenbanken verbindet, GUI-Popups anzeigt oder den Unit-Test auf andere Weise in ein vollständiges Durcheinander umwandelt, ist keine leichte Umgehung erforderlich. Eine Methode, die eine solche statische Methode aufruft, kann nicht ohne Refactoring getestet werden, selbst wenn sie eine Menge reinen Berechnungscodes enthält, für die ein Unit-Test von großem Vorteil wäre.
quelle
Ich glaube, dass Resharper Ihnen Anhaltspunkte gibt und Sie die Kodierungsrichtlinien anwenden, mit denen es eingerichtet wurde. Wenn ich Resharper verwendet habe und festgestellt habe, dass eine Methode statisch sein sollte, muss sie sich in einer privaten Methode befinden, die keine Instanzvariablen verarbeitet.
Was nun die Testbarkeit betrifft, sollte dieses Szenario kein Problem darstellen, da Sie private Methoden sowieso nicht testen sollten.
In Bezug auf die Testbarkeit von statischen Methoden, die öffentlich sind, wird das Testen von Einheiten schwierig, wenn statische Methoden den statischen Zustand berühren. Persönlich würde ich dies auf ein Minimum beschränken und statische Methoden so weit wie möglich als reine Funktionen verwenden, bei denen Abhängigkeiten in die Methode übertragen werden, die über eine Testvorrichtung gesteuert werden können. Dies ist jedoch eine Entwurfsentscheidung.
quelle