255 votes

Utilisation de Mockito pour tester les classes abstraites

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 ?

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))

6voto

Lokesh Sharma Points 145
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();
  }
}

1 votes

C'est exactement ce dont j'avais besoin - un test pour une classe abstraite avec @InjectMocks. Merci d'avoir ajouté cette réponse !

5voto

Thomas Heiss Points 21

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.

4voto

DwB Points 14687

Vous pouvez étendre la classe abstraite avec une classe anonyme dans votre test. Par exemple (en utilisant Junit 4) :

private AbstractClassName classToTest;

@Before
public void preTestSetup()
{
    classToTest = new AbstractClassName() { };
}

// Test the AbstractClassName methods.

4voto

Jorge Pastor Points 91

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.

2voto

Nick Holt Points 12945

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.

4 votes

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.

1 votes

C'est exact, la méthode ci-dessus ne fonctionnera pas si vous voulez invoquer les méthodes concrètes sur la classe abstraite.

0 votes

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.com

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.

Powered by:

X