Wie kann ich testen, private Methoden mit DUnit?
-
05-07-2019 - |
Frage
Ich habe eine Klasse, die ich Unit-Tests bin in mit DUnit. Es hat eine Reihe von Methoden, einige öffentlichen Methoden und privaten Methoden.
type
TAuth = class(TDataModule)
private
procedure PrivateMethod;
public
procedure PublicMethod;
end;
Um einen Unit-Test für diese Klasse zu schreiben, ich alle Methoden öffentlich machen.
Gibt es eine andere Möglichkeit, die privaten Methoden zu erklären, damit ich sie noch testen können, aber sie sind nicht öffentlich?
Lösung
Sie brauchen nicht, um sie öffentlich zu machen. Geschützte tun. Dann können Sie die Klasse für Unit-Tests Subtyp und die geschützten Methoden Oberfläche. Beispiel:
type
TAuth = class(TDataModule)
protected
procedure MethodIWantToUnitTest;
public
procedure PublicMethod;
end;
Jetzt können Sie es für Ihr Gerät zu testen Subtyp:
interface
uses
TestFramework, Classes, AuthDM;
type
// Test methods for class TAuthDM
TestAuthDM = class(TTestCase)
// stuff
end;
TAuthDMTester = class(TAuthDM)
public
procedure MethodIWantToUnitTestMadePublic;
end;
implementation
procedure TAuthDMTester.MethodIWantToUnitTestMadePublic;
begin
MethodIWantToUnitTest;
end;
Wenn jedoch die Methoden, die Sie Unit-Test wollen Dinge tun, so eng mit dem Datenmodul, das es nicht sicher ist, sie aber privat etwas haben, dann sollten Sie wirklich in Betracht ziehen, die Methoden, um Refactoring den Code zu trennen, die benötigt sein Einheit getestet und der Code, der die Innereien des Datenmoduls zugreift.
Andere Tipps
Es ist ein wenig hacky, aber ich denke, das ist die einfachste und klarer Ansatz. Verwenden Sie diese bedingte Kompilierung Richtlinie:
{$IfNDef TEST}
private
{$EndIf}
Ihr Unit-Test-Projekt muss TEST in project → conditional defines
definieren. Ohne Sichtbarkeit Spezifikation, werden sie veröffentlicht wurde.
Achtung: wenn die private Sicht nicht die erste in der Klassendeklaration ist, wird es die vorherige Definition erhalten. Ein sicherer Weg, aber ausführliche und weniger klar wäre:
private
{$IfDef TEST}
public
{$EndIf}
Dies hat viele Vorteile gegenüber dem Subclassing oder anderen Ansätzen:
- Keine zusätzliche Komplexität: keine zusätzlichen Klassen in Ihrem Code .
- Niemand kann „versehentlich“ Unterklasse und überschreiben Sie Ihre Klasse. Sie Ihre Architektur bewahren
- Wenn Sie eine Methode sagen geschützt ist, erwarten Sie etwas, dass es außer Kraft gesetzt werden. Sie sagen dies für den Code liest. Eine geschützte Methode, die nicht außer Kraft gesetzt werden sollte, wird die Code-Leser, bricht mir die erste Programmier Prinzip verwechseln: „Kodex muss von anderen Menschen zu lesen geschrieben werden“
- DUnit in ihrer eigenen Einheit ist, nicht überall enthalten.
- Sie berühren nicht chaotisch RTTI.
Ich denke, es ist eine klarere Lösung, und besser als die gewählten Antwort.
Als ich das verwenden, habe ich auch das Testprojekt konfigurieren, dass die Build-Objekte in einem anderen Verzeichnis des Hauptprojekts zu setzen. Dies verhindert, dass die Binärdateien mit der TEST-Richtlinie mit dem anderen Code zu mischen.
Ich empfehle die " XUnit Testmuster " Buch von Gerard Meszaros:
Frage : Wie können wir Code machen prüfbar, wenn wir zugreifen müssen privat Zustand des SUT?
Antwort : Fügen Sie Methoden, die die belichten Zustand oder Verhalten durch den Test erforderlich zu einer Unterklasse der SUT.
... Wenn das System unter Test (SUT) nicht speziell entwickelt, um prüfbare entworfen, wir können feststellen, dass der Test nicht bekommen kann Zugang zu behaupten, dass es muss initialisieren oder zu einem bestimmten Zeitpunkt überprüft in der Test.
Der Artikel erklärt auch, wenn es zu benutzen und welche Risiken es trägt.
Setzen Sie den DUnit Code innerhalb des Geräts. Sie können dann alles zugreifen Sie möchten.
In der Regel, wenn ich in diese Situation kommen, merke ich oft, dass ich die einzige Verantwortung Prinzip bin zu verletzen. Natürlich weiß ich nichts über Ihren speziellen Fall, aber vielleicht, sollen sicherstellen, dass private Methoden in ihrer eigenen Klasse sein. Die TAuth würde als einen Hinweis auf diese neue Klasse in es privaten Bereich ist.
Mit Erweiterte RTTI (Delphi 2010 und neuer) unter Berufung auf private Methoden über RTTI eine weitere Option. Diese Lösung ist auch die top-rated Antwort in Wie teste ich eine Klasse, die private Methoden hat, Felder oder innere Klassen?
{$IFNDEF UNITEST}
private
{$ENDIF}
Einfache Lösung, die kaum ein Hack ist. Ich brauche häufig private Methoden und diese Technik fügt so wenig Komplikationen wie möglich zu testen.