Ich weiß, dass Sie keine privaten Methoden testen sollen, und wenn es so aussieht, als müsste es eine Klasse geben, die darauf wartet, herauszukommen.
Aber ich möchte keine Unmengen von Klassen haben, nur damit ich ihre öffentlichen Schnittstellen testen kann, und ich finde, dass ich für viele Klassen, wenn ich nur die öffentlichen Methoden teste, am Ende viele Abhängigkeiten verspotten muss und die Unit-Tests es sind enorm und schwer zu folgen.
Ich bevorzuge es sehr, die privaten Methoden zu verspotten, wenn ich die öffentlichen teste, und externe Abhängigkeiten zu verspotten, wenn ich die privaten teste.
Bin ich verrückt?
unit-testing
mocking
Fran Sevillano
quelle
quelle
Antworten:
Sie haben teilweise recht - Sie sollten private Methoden nicht direkt testen. Die privaten Methoden einer Klasse sollten von einer oder mehreren der öffentlichen Methoden aufgerufen werden (möglicherweise indirekt - eine private Methode, die von einer öffentlichen Methode aufgerufen wird, kann andere private Methoden aufrufen). Wenn Sie Ihre öffentlichen Methoden testen, testen Sie daher auch Ihre privaten Methoden. Wenn Sie über nicht getestete private Methoden verfügen, sind entweder Ihre Testfälle unzureichend oder die privaten Methoden werden nicht verwendet und können entfernt werden.
Wenn Sie einen White-Box-Testansatz verwenden, sollten Sie die Implementierungsdetails Ihrer privaten Methoden berücksichtigen, wenn Sie Komponententests für Ihre öffentlichen Methoden erstellen. Wenn Sie einen Black-Box-Ansatz verwenden, sollten Sie keine Implementierungsdetails in den öffentlichen oder privaten Methoden testen, sondern das erwartete Verhalten.
Persönlich bevorzuge ich einen White-Box-Ansatz gegenüber Unit-Tests. Ich kann Tests erstellen, um die zu testenden Methoden und Klassen in verschiedene Zustände zu versetzen, die bei meinen öffentlichen und privaten Methoden ein interessantes Verhalten hervorrufen, und dann behaupten, dass die Ergebnisse den Erwartungen entsprechen.
Verspotten Sie also nicht Ihre privaten Methoden. Verwenden Sie sie, um zu verstehen, was Sie testen müssen, um eine gute Abdeckung der von Ihnen bereitgestellten Funktionen zu erhalten. Dies gilt insbesondere für das Unit-Test-Level.
quelle
Ich halte das für eine sehr schlechte Idee.
Das Problem bei der Erstellung von Komponententests für private Mitglieder besteht darin, dass diese schlecht zum Produktlebenszyklus passen.
Der Grund, warum Sie sich dafür entschieden haben, diese Methoden privat zu machen, liegt darin, dass sie für das, was Ihre Klassen versuchen, nicht von zentraler Bedeutung sind - nur als Hilfestellung bei der Implementierung dieser Funktionalität. Wenn Sie umgestalten, sind diese privaten Details wahrscheinlich Kandidaten für eine Änderung und verursachen dann beim Umgestalten Reibungspunkte.
Ein wesentlicher Unterschied zwischen öffentlichen und privaten Mitgliedern besteht darin, dass Sie Ihre öffentliche API sorgfältig überlegen, gut dokumentieren und prüfen sollten (Behauptungen usw.). Aber mit einer privaten API wäre es sinnlos, genau darüber nachzudenken (ein vergeudeter Aufwand, da die Verwendung so lokalisiert ist). Das Einfügen privater Methoden in Komponententests bedeutet, dass externe Abhängigkeiten von diesen Methoden erstellt werden. Dies bedeutet, dass die API stabil und gut dokumentiert sein muss (da jemand herausfinden muss, warum diese Komponententests fehlgeschlagen sind, wenn dies der Fall ist).
Ich schlage dich vor:
Schätzen Sie Ihre Neigung, diese Funktionalität zu testen, und dass es schwierig ist, sie über Ihre aktuelle öffentliche API zu testen. Aber ich persönlich schätze Modularität mehr als Testabdeckung.
quelle
UnitTests testen das öffentlich beobachtbare Verhalten , nicht den Code, wobei "öffentlich" bedeutet: Rückgabewerte und Kommunikation mit Abhängigkeiten.
Eine "Einheit" ist jeder Code, der das gleiche Problem löst (oder genauer gesagt: hat den gleichen Grund, sich zu ändern). Das kann eine einzelne Methode oder eine Reihe von Klassen sein.
Der Hauptgrund, warum Sie nicht testen möchten,
private methods
ist, dass es sich um Implementierungsdetails handelt und Sie diese möglicherweise während des Refactorings ändern möchten (verbessern Sie Ihren Code, indem Sie OO-Prinzipien anwenden, ohne die Funktionalität zu ändern). Dies ist genau der Fall, wenn Sie nicht möchten, dass sich Ihre Unittests ändern, um sicherzustellen , dass sich das Verhalten Ihres CuT während des Refactorings nicht geändert hat.Normalerweise erlebe ich das Gegenteil: Je kleiner die Klassen sind (je weniger Verantwortung sie haben), desto weniger Abhängigkeiten haben sie und desto einfacher ist es, sowohl zu schreiben als auch zu lesen.
Idealerweise wenden Sie dasselbe Abstraktionsmuster auf Ihre Klassen an. Dies bedeutet, dass Ihre Klassen entweder Geschäftslogik (vorzugsweise als "reine Funktionen", die nur an ihren Parametern arbeiten, ohne einen eigenen Zustand beizubehalten) (x) oder Methoden für andere Objekte aufrufen, nicht beide gleichzeitig.
Auf diese Weise wird das Unittesting des Geschäftsverhaltens zum Kinderspiel, und die "Delegierungs" -Objekte sind in der Regel zu einfach, um fehlzuschlagen (keine Verzweigung, keine Statusänderung), sodass kein Unittesting erforderlich ist und ihre Prüfung den Integrations- oder Modultests überlassen werden kann
quelle
Unit-Tests haben einen gewissen Wert, wenn Sie der einzige Programmierer sind, der an dem Code arbeitet, insbesondere wenn die Anwendung sehr umfangreich oder sehr komplex ist. Wenn eine größere Anzahl von Programmierern an derselben Codebasis arbeitet, sind Komponententests unabdingbar. Das Konzept des Komponententests wurde eingeführt, um einige der Schwierigkeiten bei der Arbeit in diesen größeren Teams anzugehen.
Der Grund, warum Unit-Tests größeren Teams helfen, sind Verträge. Wenn mein Code von jemand anderem geschriebenen Code anruft, gehe ich davon aus, was der Code der anderen Person in verschiedenen Situationen tun wird. Vorausgesetzt, diese Annahmen sind immer noch wahr, funktioniert mein Code immer noch. Aber woher weiß ich, welche Annahmen gültig sind und woher ich weiß, wann sich diese Annahmen geändert haben?
Hier kommen Komponententests ins Spiel. Der Autor einer Klasse erstellt Komponententests, um das erwartete Verhalten ihrer Klasse zu dokumentieren. Der Komponententest definiert alle gültigen Verwendungsarten der Klasse, und die Ausführung des Komponententests überprüft, ob diese Anwendungsfälle wie erwartet funktionieren. Ein anderer Programmierer, der von Ihrer Klasse Gebrauch machen möchte, kann Ihre Komponententests lesen, um das Verhalten zu verstehen, das er für Ihre Klasse erwarten kann, und dies als Grundlage für seine Annahmen über die Funktionsweise Ihrer Klasse verwenden.
Auf diese Weise bilden die öffentlichen Methodensignaturen der Klasse und die Komponententests zusammen einen Vertrag zwischen dem Klassenautor und den anderen Programmierern, die diese Klasse in ihrem Code verwenden.
Was passiert in diesem Szenario, wenn Sie private Methoden testen? Klar macht es keinen Sinn.
Wenn Sie der einzige Programmierer sind, der an Ihrem Code arbeitet und Unit-Tests zum Debuggen Ihres Codes verwenden möchten, sehe ich darin keinen Schaden, es ist nur ein Tool, und Sie können es so verwenden, wie es funktioniert Sie, aber es war nicht der Grund, warum Unit-Tests eingeführt wurden, und bietet nicht die Hauptvorteile von Unit-Tests.
quelle
Bevor Sie eine solche Frage beantworten, müssen Sie entscheiden, was Sie tatsächlich erreichen möchten.
Sie schreiben Code. Sie hoffen, dass es seinen Vertrag erfüllt (mit anderen Worten, es tut, was es tun soll. Das Aufschreiben dessen, was es tun soll, ist für einige Menschen ein riesiger Fortschritt).
Um einigermaßen davon überzeugt zu sein, dass der Code das tut, was er tun soll, starren Sie entweder lange genug darauf oder Sie schreiben Testcode, der genügend Fälle testet, um Sie davon zu überzeugen, dass "wenn der Code alle diese Tests besteht, ist er korrekt".
Oft interessiert Sie nur die öffentlich definierte Oberfläche eines Codes. Wenn ich Ihre Bibliothek verwenden, es ist mir egal , wie Sie es vielleicht richtig funktionieren, nur , dass es funktioniert richtig funktioniert. Ich überprüfe, ob Ihre Bibliothek korrekt ist, indem ich Komponententests durchführe.
Aber Sie erstellen die Bibliothek. Es kann schwierig sein, es richtig zum Laufen zu bringen. Angenommen, ich kümmere mich nur darum, dass die Bibliothek die Operation X korrekt ausführt, sodass ich einen Komponententest für X durchführe. Sie, der Entwickler, der für die Erstellung der Bibliothek verantwortlich ist, implementieren X, indem Sie die Schritte A, B und C kombinieren, die jeweils völlig untrivial sind. Um Ihre Bibliothek zum Laufen zu bringen, fügen Sie Tests hinzu, um zu überprüfen, ob A, B und C jeweils korrekt funktionieren. Sie wollen diese Tests. Zu sagen "Du solltest keine Unit-Tests für private Methoden haben" ist ziemlich sinnlos. Sie möchten Tests für diese privaten Methoden. Vielleicht sagt dir jemand, dass das Testen privater Methoden falsch ist. Das bedeutet aber nur, dass Sie sie möglicherweise nicht "Komponententests", sondern "private Tests" nennen oder wie auch immer Sie sie nennen möchten.
Die Sprache Swift löst das Problem, dass Sie A, B, C nicht als öffentliche Methoden verfügbar machen möchten, nur weil Sie sie testen möchten, indem Sie Funktionen das Attribut "testable" zuweisen. Der Compiler ermöglicht den Aufruf von privaten testbaren Methoden aus Unit-Tests, jedoch nicht aus Nicht-Test-Code.
quelle
Ja, du bist verrückt ... wie ein Fuchs!
Es gibt verschiedene Möglichkeiten, private Methoden zu testen, von denen einige sprachabhängig sind.
Wenn Sie jedoch private Methoden testen möchten, möchten Sie sie wahrscheinlich in Abhängigkeit von einer öffentlichen Methode verschieben und diese testen / injizieren.
quelle
Bleib pragmatisch. Das Testen von Sonderfällen in privaten Methoden, indem der Zustand der Instanz und die Parameter für eine öffentliche Methode so eingerichtet werden, dass diese Fälle dort auftreten, ist häufig viel zu kompliziert.
Ich füge einen zusätzlichen
internal
Accessor hinzu (zusammen mit dem FlagInternalsVisibleTo
der Testassembly), der eindeutig benannt istDoSomethingForTesting(parameters)
, um diese "privaten" Methoden zu testen.Natürlich kann sich die Implementierung irgendwann ändern, und diese Tests, einschließlich der Test-Accessoren, sind veraltet. Das ist immer noch besser als ungetestete Fälle oder nicht lesbare Tests.
quelle