À l'aide de Mockito pour tester les classes abstraites
Je voudrais tester une classe abstraite. Bien sûr, je peux écrire manuellement un simulacre de qui hérite de la classe.
Puis-je faire cela à l'aide d'un moqueur cadre (je suis en utilisant Mockito) au lieu de l'artisanat de ma maquette? Comment?
- Comme de Mockito 1.10.12, Mockito prend en charge l'espionnage/se moquant de classes abstraites directement:
SomeAbstract spy = spy(SomeAbstract.class);
- Comme de Mockito 2.7.14, vous pouvez aussi simuler résumé classess qui nécessitent des arguments du constructeur via
mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))
Vous devez vous connecter pour publier un commentaire.
La suggestion suivante vous permet de tester les classes abstraites sans la création d'un "réel" sous - classe- de la Maquette est la sous-classe.
utilisation
Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)
, puis se moquer de toutes les méthodes abstraites qui sont invoquées.Exemple:
Remarque: La beauté de cette solution est que vous n'avez pas ont pour mettre en œuvre les méthodes abstraites, tant qu'ils ne sont jamais invoquées.
À mon avis honnête, c'est plus propre qu'à l'aide d'un espion, depuis un espion requiert une instance, ce qui signifie que vous devez créer un instantiatable sous-classe de votre classe abstraite.
Si vous avez juste besoin de tester des méthodes concrètes sans toucher les résumés, vous pouvez utiliser
CALLS_REAL_METHODS
(voir Morten réponse), mais si la méthode concrète sous les appels de test certains des résumés ou non mises en œuvre des méthodes d'interface, cela ne fonctionne pas -- Mockito va se plaindre "Ne peut pas appeler véritable méthode sur l'interface java."(Oui, c'est une sale de conception, mais certains cadres, par exemple, de la Tapisserie 4, type de force sur vous.)
La solution de contournement consiste à inverser cette approche sur l'utilisation de l'ordinaire se moquer de comportement (c'est à dire, tout est moqué/stub) et l'utilisation
doCallRealMethod()
appeler explicitement la méthode concrète sous test. E. g.Mis à jour pour ajouter:
Pour les non-nulle méthodes, vous aurez besoin d'utiliser
thenCallRealMethod()
au lieu de cela, par exemple:Sinon Mockito va se plaindre "Inachevé stubbing détecté."
Vous pouvez atteindre cet objectif en utilisant un espion (utiliser la dernière version de Mockito de 1,8+ si).
Se moquant de cadres sont conçus pour rendre plus facile de se moquer de sortir des dépendances de la classe à tester. Lorsque vous utilisez un moqueur de cadre à un simulacre d'une classe, la plupart des cadres de créer dynamiquement une sous-classe, et de remplacer la méthode de la mise en œuvre avec le code pour détecter lorsqu'une méthode est appelée et le retour d'une fausse valeur.
Lors de l'essai d'une classe abstraite, vous souhaitez exécuter la non-résumé des méthodes de l'Objet Sous Test (SUT), donc un moqueur cadre n'est pas ce que vous voulez.
Une partie de la confusion, c'est que la réponse à la question que vous avez lié à dit, à la main, de l'artisanat, une maquette qui s'étend à partir de votre classe abstraite. Je ne dirais pas qu'une telle classe, une maquette. Une maquette est une classe qui est utilisé comme un remplacement pour une dépendance, est programmé avec les attentes, et peut être interrogé à savoir si ces attentes sont satisfaites.
Au lieu de cela, je suggère la définition d'un non-abstraite sous-classe de votre classe abstraite dans votre test. Si cela entraîne trop de code, que cela peut être un signe que votre classe est difficile à étendre.
Une solution alternative serait de prendre votre cas de test elle-même abstraite, avec une méthode abstraite pour la création de la CUS (en d'autres termes, les cas de test serait d'utiliser la Méthode De Modèle design pattern).
Essayer en utilisant une mesure de répondre.
Par exemple:
Ce sera le retour de la maquette pour les méthodes abstraites et fera appel à la vraie méthode pour les méthodes concrètes.
Ce qui fait vraiment me sentir mal à propos de se moquant de classes abstraites, c'est le fait que ni le constructeur par défaut YourAbstractClass() est appelée (manquant super() dans la maquette), ni ne semble y avoir aucun moyen de Mockito à défaut d'initialiser se moquer de propriétés (e.g Liste des propriétés vides ArrayList ou LinkedList).
Ma classe abstraite (en gros le code source de la classe est généré) ne fournit PAS une dépendance à l'injection par mutateur pour les éléments de liste, ni un constructeur où il initialise les éléments de la liste (que j'ai essayé d'ajouter manuellement).
Seulement les attributs de classe de l'utilisation d'initialisation par défaut:
Liste privée dep1 = new ArrayList;
Liste privée dep2 = new ArrayList
Il n'existe AUCUN moyen de se moquer d'une classe abstraite sans l'aide d'un objet réel de la mise en œuvre (e.g intérieure définition de la classe dans l'unité de la classe de test, surchargeant les méthodes abstraites) et de l'espionnage de l'objet réel (ce qui n'champ d'initialisation).
Dommage que seulement PowerMock permettrait ici de plus amples.
En supposant que votre test de classes sont dans le même package (en vertu d'une source différente de la racine) que vos classes en cours de test, vous pouvez simplement créer la maquette:
et appeler les méthodes que vous souhaitez tester comme vous le feriez de toute autre méthode.
Vous devez fournir les attentes pour chaque méthode est appelée avec l'attente sur toutes les méthodes concrètes de l'appel de la méthode super - ne sais pas comment vous pouvez le faire avec Mockito, mais je crois que c'est possible avec EasyMock.
Tout cela est en train de faire est de créer un béton instance de
YouClass
et vous économisez de l'effort de fournir des implémentations vides de chaque méthode abstraite.En aparté, je trouve souvent qu'il est utile de mettre en œuvre la classe abstraite dans mon test, où il sert comme un exemple de mise en oeuvre que je test via son interface publique, bien que cela dépendra de la fonctionnalité fournie par la classe abstraite.
Vous pouvez étendre la classe abstraite avec une classe anonyme dans votre test.
Par exemple (en utilisant Junit 4):
Vous pouvez instancier une classe anonyme, injecter, se moque de puis de tester cette classe.
Gardez à l'esprit que la visibilité doit être
protected
pour le bienmyDependencyService
de la classe abstraiteClassUnderTest
.Whitebox.invokeMethod(..) peut être utile dans ce cas.
Mockito permet de se moquant de classes abstraites par le biais de la
@Mock
annotation:L'inconvénient est qu'il ne peut pas être utilisé si vous avez besoin de paramètres du constructeur.