Wie testest du eine private Funktion in Winkel 2?
class FooBar {
private _status: number;
constructor( private foo : Bar ) {
this.initFooBar();
}
private initFooBar(){
this.foo.bar( "data" );
this._status = this.fooo.foo();
}
public get status(){
return this._status;
}
}
Die Lösung, die ich gefunden habe
Fügen Sie den Testcode selbst in den Abschluss ein oder fügen Sie Code in den Abschluss ein, in dem Verweise auf die lokalen Variablen für vorhandene Objekte im äußeren Bereich gespeichert sind.
Entfernen Sie später den Testcode mit einem Werkzeug. http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/
Bitte schlagen Sie mir einen besseren Weg vor, um dieses Problem zu lösen, wenn Sie welche getan haben.
PS
Die meisten Antworten auf ähnliche Fragen wie diese geben keine Lösung für das Problem. Deshalb stelle ich diese Frage
Die meisten Entwickler sagen, dass Sie keine privaten Funktionen testen, aber ich sage nicht, dass sie falsch oder richtig sind, aber es gibt Notwendigkeiten für meinen Fall, um private Funktionen zu testen.
quelle
Antworten:
Ich bin bei Ihnen, obwohl es ein gutes Ziel ist, "nur die öffentliche API zu testen", gibt es Zeiten, in denen es nicht so einfach erscheint und Sie das Gefühl haben, zwischen einer Kompromittierung der API oder der Komponententests zu wählen. Sie wissen das bereits, da Sie genau darum bitten, also werde ich nicht darauf eingehen. :) :)
In TypeScript habe ich einige Möglichkeiten entdeckt, wie Sie zum Testen von Einheiten auf private Mitglieder zugreifen können. Betrachten Sie diese Klasse:
Obwohl TS den Zugriff auf die Teilnehmer , mit
private
,protected
,public
, hat die kompilierte JS keine privaten Mitglieder, da dies nicht eine Sache in JS ist. Es wird ausschließlich für den TS-Compiler verwendet. Dafür:Sie können
any
dem Compiler versichern, dass er Sie vor Zugriffsbeschränkungen warnt:Das Problem bei diesem Ansatz ist, dass der Compiler einfach keine Ahnung hat, was Sie richtig machen
any
, sodass Sie nicht die gewünschten Typfehler erhalten:Dies wird das Refactoring offensichtlich schwieriger machen.
Sie können array access (
[]
) verwenden, um zu den privaten Mitgliedern zu gelangen:Während es funky aussieht, überprüft TSC die Typen tatsächlich so, als hätten Sie direkt darauf zugegriffen:
Um ehrlich zu sein, weiß ich nicht, warum das funktioniert.Dies ist anscheinend eine absichtliche "Notluke" , um Ihnen Zugang zu privaten Mitgliedern zu verschaffen, ohne die Typensicherheit zu verlieren. Genau das möchten Sie meiner Meinung nach für Ihre Unit-Tests.Hier ist ein Arbeitsbeispiel auf dem TypeScript-Spielplatz .
Bearbeiten für TypeScript 2.6
Eine andere Option, die manche mögen, ist die Verwendung
// @ts-ignore
( hinzugefügt in TS 2.6 ), die einfach alle Fehler in der folgenden Zeile unterdrückt:Das Problem dabei ist, dass alle Fehler in der folgenden Zeile unterdrückt werden:
Ich persönlich betrachte
@ts-ignore
einen Code-Geruch und wie die Dokumente sagen:quelle
as any
: Sie verlieren alle Typprüfungen.Sie können private Methoden aufrufen . Wenn Sie den folgenden Fehler festgestellt haben:
benutze einfach
// @ts-ignore
:quelle
as any
dass Sie jede Typprüfung verlieren, tatsächlich verlieren Sie jede Typprüfung in der gesamten Zeile.Da die meisten Entwickler nicht empfehlen, die private Funktion zu testen, sollten Sie sie testen.
Z.B.
YourClass.ts
TestYourClass.spec.ts
Vielen Dank an @Aaron, @Thierry Templier.
quelle
Schreiben Sie keine Tests für private Methoden. Dies macht den Punkt von Unit-Tests zunichte.
Beispiel
Der Test für diese Methode sollte nicht geändert werden müssen, wenn sich später die Implementierung ändert,
behaviour
die öffentliche API jedoch unverändert bleibt.Machen Sie Methoden und Eigenschaften nicht öffentlich, nur um sie zu testen. Dies bedeutet normalerweise, dass entweder:
quelle
Der Punkt "Private Methoden nicht testen" ist wirklich, die Klasse wie jemand zu testen , der sie verwendet .
Wenn Sie eine öffentliche API mit 5 Methoden haben, kann jeder Verbraucher Ihrer Klasse diese verwenden. Daher sollten Sie sie testen. Ein Verbraucher sollte nicht auf die privaten Methoden / Eigenschaften Ihrer Klasse zugreifen. Dies bedeutet, dass Sie private Mitglieder ändern können, wenn die öffentlich zugängliche Funktionalität gleich bleibt.
Wenn Sie sich auf interne erweiterbare Funktionen verlassen, verwenden Sie
protected
stattdessenprivate
.Beachten Sie, dass dies
protected
immer noch eine öffentliche API (!) Ist , die nur anders verwendet wird.Unit-Test-geschützte Eigenschaften auf die gleiche Weise, wie ein Verbraucher sie verwenden würde, über Unterklassen:
quelle
Das hat bei mir funktioniert:
Anstatt:
Dies:
quelle
Entschuldigen Sie den Nekro in diesem Beitrag, aber ich fühle mich gezwungen, ein paar Dinge abzuwägen, die anscheinend nicht berührt wurden.
In erster Linie - wenn wir während des Unit-Tests Zugang zu privaten Mitgliedern einer Klasse benötigen, ist dies im Allgemeinen eine große, fette rote Fahne, die wir in unserem strategischen oder taktischen Ansatz vermasselt haben und versehentlich durch Druck auf das Prinzip der Einzelverantwortung verstoßen haben Verhalten, wo es nicht hingehört. Das Gefühl, auf Methoden zugreifen zu müssen, die eigentlich nichts anderes als eine isolierte Unterroutine eines Konstruktionsverfahrens sind, ist eines der häufigsten Ereignisse. Es ist jedoch so, als würde Ihr Chef erwarten, dass Sie bereit zur Arbeit erscheinen und auch pervers wissen müssen, welche Morgenroutine Sie durchlaufen haben, um in diesen Zustand zu gelangen ...
Das andere häufigste Beispiel dafür ist, dass Sie versuchen, die sprichwörtliche "Gottklasse" zu testen. Es ist an und für sich eine besondere Art von Problem, leidet jedoch unter dem gleichen Grundproblem, wenn man intime Details eines Verfahrens kennen muss - aber das kommt vom Thema ab.
In diesem speziellen Beispiel haben wir die Verantwortung für die vollständige Initialisierung des Bar-Objekts effektiv dem Konstruktor der FooBar-Klasse zugewiesen. Bei der objektorientierten Programmierung ist einer der Hauptgründe, dass der Konstruktor "heilig" ist und vor ungültigen Daten geschützt werden sollte, die seinen eigenen internen Zustand ungültig machen und ihn darauf vorbereiten würden, irgendwo anders stromabwärts zu versagen (in einer möglicherweise sehr tiefen Situation) Pipeline.)
Wir haben dies hier nicht getan, indem wir dem FooBar-Objekt erlaubt haben, einen Balken zu akzeptieren, der zum Zeitpunkt der Erstellung der FooBar noch nicht bereit ist, und dies durch eine Art "Hacking" des FooBar-Objekts kompensiert haben, um die Dinge selbst in die Hand zu nehmen Hände.
Dies ist das Ergebnis eines Versäumnisses, sich an einen anderen Tenent der objektorientierten Programmierung zu halten (im Fall von Bar). Dies bedeutet, dass der Status eines Objekts vollständig initialisiert und bereit sein sollte, eingehende Anrufe an seine öffentlichen Mitglieder unmittelbar nach der Erstellung zu verarbeiten. Dies bedeutet nicht, dass der Konstruktor in allen Fällen unmittelbar aufgerufen wird. Wenn Sie ein Objekt mit vielen komplexen Konstruktionsszenarien haben, ist es besser, Setter seinen optionalen Elementen einem Objekt auszusetzen, das gemäß einem Erstellungsentwurfsmuster (Factory, Builder usw.) in einem der folgenden Elemente implementiert ist die letzteren Fälle,
In Ihrem Beispiel scheint sich die Eigenschaft "status" der Leiste nicht in einem gültigen Zustand zu befinden, in dem eine FooBar sie akzeptieren kann. Die FooBar unternimmt also etwas, um dieses Problem zu beheben.
Das zweite Problem, das ich sehe, ist, dass Sie anscheinend versuchen, Ihren Code zu testen, anstatt eine testgetriebene Entwicklung zu üben. Dies ist definitiv meine eigene Meinung zu diesem Zeitpunkt; Aber diese Art des Testens ist wirklich ein Anti-Muster. Am Ende geraten Sie in die Falle, zu erkennen, dass Sie Kernprobleme beim Design haben, die verhindern, dass Ihr Code nachträglich testbar ist, anstatt die benötigten Tests zu schreiben und anschließend auf die Tests zu programmieren. In jedem Fall sollten Sie immer noch die gleiche Anzahl von Tests und Codezeilen haben, wenn Sie wirklich eine SOLID-Implementierung erreicht haben. Warum also versuchen, Ihren Weg in testbaren Code zurückzuentwickeln, wenn Sie die Angelegenheit zu Beginn Ihrer Entwicklungsbemühungen nur ansprechen können?
Wenn Sie das getan hätten, hätten Sie viel früher erkannt, dass Sie einen ziemlich ekligen Code schreiben müssten, um gegen Ihr Design zu testen, und hätten frühzeitig die Möglichkeit gehabt, Ihren Ansatz neu auszurichten, indem Sie das Verhalten auf Implementierungen verlagerten, die dies tun sind leicht testbar.
quelle
Ich stimme @toskv zu: Ich würde das nicht empfehlen :-)
Wenn Sie Ihre private Methode jedoch wirklich testen möchten, können Sie sich darüber im Klaren sein, dass der entsprechende Code für das TypeScript einer Methode des Prototyps der Konstruktorfunktion entspricht. Dies bedeutet, dass es zur Laufzeit verwendet werden kann (während Sie wahrscheinlich einige Kompilierungsfehler haben werden).
Beispielsweise:
wird transpiliert in:
Siehe diesen Plunkr: https://plnkr.co/edit/calJCF?p=preview .
quelle
Wie viele bereits gesagt haben, sollten Sie Ihren Code oder Transpiler nicht hacken, damit er für Sie funktioniert, so oft Sie die privaten Methoden testen möchten. Das heutige TypeScript wird fast alle Hacks ablehnen, die die Leute bisher bereitgestellt haben.
Lösung
TLDR ; Wenn eine Methode getestet werden soll, sollten Sie den Code in eine Klasse entkoppeln, mit der Sie die zu testende Methode öffentlich machen können.
Der Grund, warum Sie die Methode privat haben, ist, dass die Funktionalität nicht unbedingt von dieser Klasse verfügbar gemacht werden muss. Wenn die Funktionalität nicht dorthin gehört, sollte sie daher in ihre eigene Klasse entkoppelt werden.
Beispiel
Ich bin auf diesen Artikel gestoßen, der hervorragend erklärt, wie Sie das Testen privater Methoden angehen sollten. Es werden sogar einige der Methoden hier behandelt und wie sie schlechte Implementierungen sind.
https://patrickdesjardins.com/blog/how-to-unit-test-private-method-in-typescript-part-2
Hinweis : Dieser Code wird aus dem oben verlinkten Blog entfernt (ich dupliziere, falls sich der Inhalt hinter dem Link ändert).
Vor Nach demquelle
Rufen Sie die private Methode in eckigen Klammern auf
Ts-Datei
spect.ts Datei
quelle
Die Antwort von Aaron ist die beste und funktioniert für mich :) Ich würde darüber abstimmen, aber leider kann ich nicht (fehlender Ruf).
Ich muss sagen, dass das Testen privater Methoden die einzige Möglichkeit ist, sie zu verwenden und auf der anderen Seite sauberen Code zu haben.
Beispielsweise:
Es ist sehr sinnvoll, nicht alle diese Methoden auf einmal zu testen, da wir diese privaten Methoden verspotten müssten, die wir nicht verspotten können, weil wir nicht auf sie zugreifen können. Dies bedeutet, dass wir viel Konfiguration für einen Komponententest benötigen, um dies als Ganzes zu testen.
Der beste Weg, um die oben beschriebene Methode mit allen Abhängigkeiten zu testen, ist ein End-to-End-Test, da hier ein Integrationstest erforderlich ist. Der E2E-Test hilft Ihnen jedoch nicht, wenn Sie TDD (Test Driven Development) üben, sondern testen jede Methode wird.
quelle
Auf diesem Weg erstelle ich Funktionen außerhalb der Klasse und ordne die Funktion meiner privaten Methode zu.
Jetzt weiß ich nicht, gegen welche Art von OOP-Regeln ich verstoße, aber um die Frage zu beantworten, teste ich auf diese Weise private Methoden. Ich begrüße jeden, der diesbezüglich Vor- und Nachteile berät.
quelle