J'aimerais tester une classe abstraite. Bien sûr, je peux écrire manuellement un simulateur qui hérite de la classe.
Puis-je le faire en utilisant un framework de mocking (j'utilise Mockito) au lieu de créer manuellement mon mock ? Comment ?
J'aimerais tester une classe abstraite. Bien sûr, je peux écrire manuellement un simulateur qui hérite de la classe.
Puis-je le faire en utilisant un framework de mocking (j'utilise Mockito) au lieu de créer manuellement mon mock ? Comment ?
class Dependency{
public void method(){};
}
public abstract class My {
private Dependency dependency;
public abstract boolean myAbstractMethod();
public void myNonAbstractMethod() {
// ...
dependency.method();
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@InjectMocks
private My my = Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS);
// we can mock dependencies also here
@Mock
private Dependency dependency;
@Test
private void shouldPass() {
// can be mock the dependency object here.
// It will be useful to test non abstract method
my.myNonAbstractMethod();
}
}
Ce qui me gêne vraiment dans l'utilisation des classes abstraites est le fait que ni le constructeur par défaut YourAbstractClass()
est appelé (manquant super()
dans mock) et il ne semble pas y avoir de moyen dans Mockito d'initialiser par défaut les propriétés de mock (par ex. List
avec des propriétés vides ArrayList
o LinkedList
).
Ma classe abstraite (essentiellement la classe dont le code source est généré) ne fournit PAS d'injection de setter de dépendance pour les éléments de liste, ni de constructeur où elle initialise les éléments de liste (ce que j'ai essayé d'ajouter manuellement).
Seuls les attributs de classe utilisent l'initialisation par défaut :
private List<MyGenType> dep1 = new ArrayList<MyGenType>();
private List<MyGenType> dep2 = new ArrayList<MyGenType>();
Il n'y a donc AUCUN moyen de simuler une classe abstraite sans utiliser une implémentation d'un objet réel (par exemple, une définition de classe interne dans une classe de test unitaire, en surchargeant les méthodes abstraites) et en espionnant l'objet réel (qui effectue l'initialisation correcte des champs).
Dommage que seulement PowerMock aiderait davantage ici.
Mockito permet de simuler des classes abstraites à l'aide de la fonction @Mock
annotation :
public abstract class My {
public abstract boolean myAbstractMethod();
public void myNonAbstractMethod() {
// ...
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(answer = Answers.CALLS_REAL_METHODS)
private My my;
@Test
private void shouldPass() {
BDDMockito.given(my.myAbstractMethod()).willReturn(true);
my.myNonAbstractMethod();
// ...
}
}
L'inconvénient est qu'il ne peut pas être utilisé si vous avez besoin de paramètres de constructeur.
En supposant que vos classes de test se trouvent dans le même paquet (sous un Root source différent) que vos classes à tester, vous pouvez simplement créer l'objet fantaisie :
YourClass yourObject = mock(YourClass.class);
et appelez les méthodes que vous voulez tester comme vous le feriez pour n'importe quelle autre méthode.
Vous devez fournir des attentes pour chaque méthode qui est appelée avec l'attente sur toutes les méthodes concrètes appelant la super méthode - je ne suis pas sûr de savoir comment faire cela avec Mockito, mais je crois que c'est possible avec EasyMock.
Tout ce que cela fait est de créer une instance concrète de YouClass
et vous épargner l'effort de fournir des implémentations vides de chaque méthode abstraite.
Par ailleurs, 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 de la fonctionnalité fournie par la classe abstraite.
Mais l'utilisation de l'objet fantaisie ne testera pas les méthodes concrètes de YourClass, ou bien ai-je tort ? Ce n'est pas ce que je recherche.
C'est exact, la méthode ci-dessus ne fonctionnera pas si vous voulez invoquer les méthodes concrètes sur la classe abstraite.
Mes excuses, je vais modifier la partie concernant l'attente, qui est requise pour chaque méthode que vous appelez et pas seulement pour les méthodes abstraites.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
6 votes
A partir de Mockito 1.10.12 Mockito prend en charge l'espionnage/le moquage des classes abstraites directement :
SomeAbstract spy = spy(SomeAbstract.class);
15 votes
Depuis la version 2.7.14 de Mockito, vous pouvez également simuler les classes abstraites qui nécessitent des arguments de constructeur par l'intermédiaire de
mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))