Je voudrais tester une classe abstraite. Bien sûr, je peux écrire manuellement une maquette qui hérite de la classe.
Puis-je faire cela en utilisant un cadre de simulation (j'utilise Mockito) au lieu de fabriquer ma maquette à la main? Comment?
java
unit-testing
mocking
abstract-class
mockito
ripper234
la source
la source
SomeAbstract spy = spy(SomeAbstract.class);
mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))
Réponses:
La suggestion suivante vous permet de tester des classes abstraites sans créer une "vraie" sous-classe - le Mock est la sous-classe.
utiliser
Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)
, puis se moquer de toutes les méthodes abstraites qui sont invoquées.Exemple:
Note: La beauté de cette solution est que vous ne devez mettre en œuvre les méthodes abstraites, tant qu'ils ne sont jamais invoquées.
À mon avis, c'est plus simple que d'utiliser un espion, car un espion nécessite une instance, ce qui signifie que vous devez créer une sous-classe instanciable de votre classe abstraite.
la source
Si vous avez juste besoin de tester certaines des méthodes concrètes sans toucher à aucun des résumés, vous pouvez utiliser
CALLS_REAL_METHODS
(voir la réponse de Morten ), mais si la méthode concrète testée appelle certains des résumés ou des méthodes d'interface non implémentées, cela ne fonctionnera pas - Mockito se plaindra "Impossible d'appeler la méthode réelle sur l'interface java."(Oui, c'est un design moche, mais certains frameworks, par exemple Tapestry 4, le forcent sur vous.)
La solution de contournement consiste à inverser cette approche - utilisez le comportement de simulation ordinaire (c'est-à-dire que tout est moqué / tronqué) et utilisez
doCallRealMethod()
pour appeler explicitement la méthode concrète testée. Par exempleMis à jour pour ajouter:
Pour les méthodes non nulles, vous devrez utiliser à la
thenCallRealMethod()
place, par exemple:Sinon, Mockito se plaindra "Détection de stubbing inachevé".
la source
Vous pouvez y parvenir en utilisant un espion (utilisez cependant la dernière version de Mockito 1.8+).
la source
Les frameworks de simulation sont conçus pour faciliter la simulation des dépendances de la classe que vous testez. Lorsque vous utilisez un framework de simulation pour simuler une classe, la plupart des frameworks créent dynamiquement une sous-classe et remplacent l'implémentation de la méthode par du code pour détecter le moment où une méthode est appelée et renvoyer une fausse valeur.
Lorsque vous testez une classe abstraite, vous souhaitez exécuter les méthodes non abstraites du sujet en cours de test (SUT), donc un cadre de simulation n'est pas ce que vous voulez.
Une partie de la confusion réside dans le fait que la réponse à la question à laquelle vous avez lié a dit de fabriquer à la main une maquette qui s'étend de votre classe abstraite. Je n'appellerais pas une telle classe un simulacre. Une maquette est une classe qui est utilisée en remplacement d'une dépendance, est programmée avec des attentes et peut être interrogée pour voir si ces attentes sont satisfaites.
Au lieu de cela, je suggère de définir une sous-classe non abstraite de votre classe abstraite dans votre test. Si cela entraîne trop de code, cela peut être un signe que votre classe est difficile à étendre.
Une solution alternative serait de rendre votre cas de test lui-même abstrait, avec une méthode abstraite pour créer le SUT (en d'autres termes, le cas de test utiliserait le modèle de conception de la méthode de modèle).
la source
Essayez d'utiliser une réponse personnalisée.
Par exemple:
Il retournera la maquette pour les méthodes abstraites et appellera la vraie méthode pour les méthodes concrètes.
la source
Ce qui me fait vraiment du mal à me moquer des classes abstraites, c'est le fait que ni le constructeur par défaut YourAbstractClass () n'est appelé (il manque super () dans mock) ni qu'il n'y a aucun moyen dans Mockito d'initialiser par défaut les propriétés fictives (par exemple, les propriétés List avec ArrayList ou LinkedList vide).
Ma classe abstraite (essentiellement le code source de la classe est générée) ne fournit PAS d'injection de définition de dépendance pour les éléments de liste, ni de constructeur où elle initialise les éléments de liste (que j'ai essayé d'ajouter manuellement).
Seuls les attributs de classe utilisent l'initialisation par défaut: private List dep1 = new ArrayList; Liste privée dep2 = new ArrayList
Il n'y a donc AUCUN moyen de se moquer d'une classe abstraite sans utiliser une implémentation d'objet réel (par exemple la définition de classe interne dans la classe de test unitaire, les méthodes abstraites écrasantes) et l'espionnage de l'objet réel (qui effectue l'initialisation correcte du champ).
Dommage que seul PowerMock puisse aider encore plus.
la source
En supposant que vos classes de test sont dans le même package (sous une racine source différente) que vos classes sous test, vous pouvez simplement créer la maquette:
et appelez les méthodes que vous souhaitez tester comme vous le feriez pour toute autre méthode.
Vous devez fournir des attentes pour chaque méthode appelée avec l'attente de toute méthode concrète appelant la super méthode - je ne sais pas comment vous le feriez avec Mockito, mais je crois que c'est possible avec EasyMock.
Tout cela crée une instance concrète
YouClass
et vous évite de fournir des implémentations vides de chaque méthode abstraite.En passant, je trouve souvent utile d'implémenter la classe abstraite dans mon test, où elle sert d'exemple d'implémentation que je teste via son interface publique, bien que cela dépende des fonctionnalités fournies par la classe abstraite.
la source
Vous pouvez étendre la classe abstraite avec une classe anonyme dans votre test. Par exemple (en utilisant Junit 4):
la source
Mockito permet de se moquer des classes abstraites au moyen de l'
@Mock
annotation:L'inconvénient est qu'il ne peut pas être utilisé si vous avez besoin de paramètres de constructeur.
la source
Vous pouvez instancier une classe anonyme, injecter vos simulacres puis tester cette classe.
Gardez à l'esprit que la visibilité doit être
protected
pour la propriétémyDependencyService
de la classe abstraiteClassUnderTest
.la source
Les PowerMock
Whitebox.invokeMethod(..)
peuvent être utiles dans ce cas.la source