Quelle est la meilleure façon d'écrire des tests junit pour les interfaces afin qu'ils puissent être utilisés pour les classes d'implémentation concrètes ?
Par exemple, vous avez cette interface et des classes d'implémentation :
public interface MyInterface {
/** Return the given value. */
public boolean myMethod(boolean retVal);
}
public class MyClass1 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
public class MyClass2 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
Comment écrire un test contre l'interface afin de pouvoir l'utiliser pour la classe ?
Possibilité 1 :
public abstract class MyInterfaceTest {
public abstract MyInterface createInstance();
@Test
public final void testMyMethod_True() {
MyInterface instance = createInstance();
assertTrue(instance.myMethod(true));
}
@Test
public final void testMyMethod_False() {
MyInterface instance = createInstance();
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass1();
}
}
public class MyClass2Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass2();
}
}
Pro :
- Une seule méthode doit être mise en œuvre
Con :
- Les dépendances et les objets fantaisie de la classe à tester doivent être les mêmes pour tous les tests.
Possibilité 2 :
public abstract class MyInterfaceTest
public void testMyMethod_True(MyInterface instance) {
assertTrue(instance.myMethod(true));
}
public void testMyMethod_False(MyInterface instance) {
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
@Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass1();
super.testMyMethod_True(instance);
}
@Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass1();
super.testMyMethod_False(instance);
}
}
public class MyClass2Test extends MyInterfaceTest {
@Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass2();
super.testMyMethod_True(instance);
}
@Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass2();
super.testMyMethod_False(instance);
}
}
Pro :
- granularité fine pour chaque test, y compris les dépendances et les objets fantaisie.
Con :
- Chaque classe de test implémentée nécessite d'écrire des méthodes de test supplémentaires.
Quelle possibilité préférez-vous ou quel autre moyen utilisez-vous ?
0 votes
La possibilité 1 n'est pas suffisante lorsque la classe concrète se trouve dans un paquet, un composant ou une équipe de développement différents.
1 votes
@AndyThomas : Pourquoi dites-vous cela ? J'utilise la possibilité 1 avec des classes concrètes (à la fois pour les implémentations et les tests) dans différents paquets et projets Maven.
1 votes
@TrevorRobinson - En repensant à ce commentaire vieux de trois ans, tout ce qui me vient à l'esprit pour le moment est que les classes hors de votre contrôle peuvent avoir de multiples constructeurs, mais la possibilité 1 exécute chaque test sur un objet créé uniquement avec l'un d'entre eux.
0 votes
Avec l'option 1, vous pouvez avoir des méthodes @Before distinctes dans chaque classe concrète. Vous pouvez également avoir des tests ponctuels dans les classes concrètes comme bon vous semble.
0 votes
Les annotations de test dans les interfaces sont désormais possibles dans JUnit 5 et fonctionnent comme prévu.
0 votes
@StevenJeuris cette question ne concerne pas l'ajout d'annotations à "Test interfaces", mais plutôt le test d'interfaces réelles.
0 votes
@GMeister Que sont les "vraies" interfaces ? Dans JUnit 5, vous pouvez créer une interface et y ajouter des tests. Par la suite, vous pouvez étendre l'interface et les tests spécifiés dans l'interface seront exécutés sur la classe concrète.
0 votes
@StevenJeuris Si j'ai bien compris, vous parlez des interfaces JUnit, c'est-à-dire des interfaces à utiliser par les tests JUnit - du moins c'est ce à quoi votre lien fait référence. Cette question porte plutôt sur le test des Interfaces du code fonctionnel (par opposition au code de test).