Comment puis-je tester des méthodes privées avec DUnit?
-
05-07-2019 - |
Question
J'ai une classe dans laquelle je suis en train de tester avec DUnit. Il a un certain nombre de méthodes dont des méthodes publiques et des méthodes privées.
type
TAuth = class(TDataModule)
private
procedure PrivateMethod;
public
procedure PublicMethod;
end;
Pour écrire un test unitaire pour cette classe, je dois rendre toutes les méthodes publiques.
Existe-t-il un moyen différent de déclarer les méthodes privées afin que je puisse toujours les tester mais elles ne sont pas publiques?
La solution
Vous n'avez pas besoin de les rendre publics. Protégé va faire. Ensuite, vous pouvez sous-taper la classe pour le test unitaire et afficher les méthodes protégées. Exemple:
type
TAuth = class(TDataModule)
protected
procedure MethodIWantToUnitTest;
public
procedure PublicMethod;
end;
Vous pouvez maintenant le sous-taper pour votre test unitaire:
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;
Toutefois, si les méthodes que vous souhaitez tester unitairement effectuent des opérations si intimement liées au module de données qu'il n'est pas sûr de les utiliser autrement que de manière privée, vous devez vraiment envisager de refactoriser les méthodes afin de séparer le code nécessaire. à tester et le code qui accède aux entrailles du module de données.
Autres conseils
C’est un peu hacky, mais je pense que c’est l’approche la plus simple et la plus claire. Utilisez cette directive de compilation conditionnelle:
{$IfNDef TEST}
private
{$EndIf}
Votre projet de test unitaire doit définir TEST dans projet & # 8594; conditionnel définit
. Sans spécification de visibilité, ils sont publiés.
Attention: si la visibilité privée n’est pas la première de la déclaration de classe, elle aura la définition précédente. Une manière plus sûre, mais plus verbeuse et moins claire, serait:
private
{$IfDef TEST}
public
{$EndIf}
Cela présente de nombreux avantages par rapport au sous-classement ou à d’autres approches:
- Aucune complexité supplémentaire: pas de classes supplémentaires dans votre code.
- Personne ne peut "faire une erreur". sous-classe et remplacez votre classe: vous conservez votre architecture.
- Lorsque vous dites qu'une méthode est protégée, vous vous attendez un peu à ce qu'elle soit remplacée. Vous dites ceci pour qui lit votre code. Une méthode protégée qui ne doit pas être remplacée confondra vos lecteurs de code, ce qui violera mon premier principe de programmation: "Le code doit être écrit pour être lu par d'autres êtres humains."
- DUnit est dans sa propre unité, non incluse partout.
- Vous ne touchez pas RTTI en désordre.
Je pense que c'est une solution plus claire et meilleure que la réponse choisie.
Lorsque je l'utilise, je configure également le projet de test pour qu'il mette les objets de construction dans un autre répertoire du projet principal. Ceci empêche les fichiers binaires avec la directive TEST de se mélanger avec l’autre code.
Je recommande les " modèles de test XUnit " livre de Gerard Meszaros:
sous-classe spécifique au test
Question : Comment créer du code? testable lorsque nous avons besoin d'accéder état privé du SUT?
Réponse : ajoutez des méthodes exposant le état ou comportement requis par le test dans une sous-classe de SUT.
... Si le système testé (SUT) n'était pas conçu spécifiquement pour être testable, nous pouvons trouver que le test ne peut pas obtenir accès à déclarer qu'il doit initialiser ou vérifier à un moment donné le test.
L'article explique également quand l'utiliser et quels risques il comporte.
Mettez le code DUnit dans votre unité. Vous pouvez ensuite accéder à tout ce que vous voulez.
En général, lorsque je me retrouve dans cette situation, je me rends souvent compte que je viole le principe de responsabilité unique. Bien sûr, je ne connais rien à votre cas particulier, mais PEUT-ÊTRE, que les méthodes privées doivent être dans leur propre classe. Le TAuth aurait alors une référence à cette nouvelle classe dans sa section privée.
Avec RTTI étendu (Delphi 2010 et versions ultérieures), l’appel de méthodes privées via RTTI est une autre option. Cette solution est également la réponse la mieux notée dans Comment tester une classe contenant des méthodes privées, des champs ou des classes internes?
{$IFNDEF UNITEST}
private
{$ENDIF}
Solution simple, qui est à peine un hack. J'ai souvent besoin de tester des méthodes privées et cette technique ajoute le moins de complications possible.