99 votes

Comment tester une classe abstraite en Java avec JUnit ?

Je suis novice en matière de tests Java avec JUnit. Je dois travailler avec Java et j'aimerais utiliser des tests unitaires.

Mon problème est le suivant : j'ai une classe abstraite avec quelques méthodes abstraites. Mais il y a des méthodes qui ne sont pas abstraites. Comment puis-je tester cette classe avec JUnit ? Exemple de code (très simple) :

abstract class Car {

    public Car(int speed, int fuel) {
        this.speed = speed;
        this.fuel = fuel;
    }

    private int speed;
    private int fuel;

    abstract void drive();

    public int getSpeed() {
        return this.speed;
    }

    public int getFuel() {
        return this.fuel;
    }
}

Je veux tester getSpeed() y getFuel() fonctions.

Une question similaire à ce problème est aquí mais il n'utilise pas JUnit.

Dans la section FAQ de JUnit, j'ai trouvé ce lien mais je ne comprends pas ce que l'auteur veut dire avec cet exemple. Que signifie cette ligne de code ?

public abstract Source getSource() ;

5 votes

Voir stackoverflow.com/questions/1087339/ pour deux solutions utilisant Mockito.

0 votes

Y a-t-il un avantage à apprendre un autre framework pour les tests ? Mockito est-il seulement une extension de jUnit, ou un projet complètement différent ?

0 votes

Mockito ne remplace pas JUnit. Comme les autres frameworks de mocking, il est utilisé en complément d'un framework de test unitaire et vous aide à créer des objets fantaisie à utiliser dans vos scénarios de test.

114voto

nsfyn55 Points 4753

Si vous n'avez pas d'implémentations concrètes de la classe et que les méthodes ne sont pas static Quel est l'intérêt de les tester ? Si vous avez une classe concrète, vous testerez ces méthodes dans le cadre de l'API publique de la classe concrète.

Je sais ce que vous pensez "Je ne veux pas tester ces méthodes encore et encore c'est la raison pour laquelle j'ai créé la classe abstraite", mais mon contre argument est que le but des tests unitaires est de permettre aux développeurs de faire des changements, d'exécuter les tests et d'analyser les résultats. Une partie de ces changements pourrait inclure le remplacement des méthodes de votre classe abstraite, à la fois protected y public qui pourraient entraîner des changements comportementaux fondamentaux. Selon la nature de ces changements, ils pourraient affecter le fonctionnement de votre application de manière inattendue, voire négative. Si vous disposez d'une bonne suite de tests unitaires, les problèmes découlant de ces types de changements devraient être apparents au moment du développement.

0 votes

Vous avez tout à fait raison. Je n'y avais pas pensé de cette façon. J'ai juste pensé qu'il était bon d'avoir une combinaison de test pour chaque classe du projet, afin d'être sûr que chaque classe fonctionne comme je le suppose.

23 votes

Une couverture de code à 100% est un mythe. Vous devriez avoir exactement assez de tests pour couvrir toutes vos hypothèses connues sur la façon dont votre application devrait se comporter (de préférence écrits avant d'écrire le code, comme dans le cas du développement piloté par les tests). Je travaille actuellement dans une équipe de développement piloté par les tests (TDD) très performante et nous n'avons que 63% de couverture à partir de notre dernier build, tous écrits au fur et à mesure du développement. Est-ce bon ? qui sait ? mais je considérerais comme une perte de temps de revenir en arrière et d'essayer d'augmenter ce taux.

0 votes

J'éviterais la duplication des tests et déclarerais les méthodes comme finales lorsque cela s'applique. Le revers de la médaille est que vous devrez modifier plusieurs tests si vous décidez de remanier ou de modifier la fonction de la classe abstraite.

43voto

Kevin Bowersox Points 48223

Créez une classe concrète qui hérite de la classe abstraite, puis testez les fonctions que la classe concrète hérite de la classe abstraite.

1 votes

Que feriez-vous dans le cas où vous auriez 10 classes concrètes étendant la classe abstraite et que chacune de ces classes concrètes implémenterait seulement 1 méthode et disons que les 2 autres méthodes sont les mêmes pour chacune de ces classes, parce qu'elles sont implémentées dans la classe abstraite ? Mon cas est que je ne veux pas copier-coller les tests de la classe abstraite dans chaque sous-classe.

14voto

Grodriguez Points 9945

Avec l'exemple de classe que vous avez posté, il ne semble pas très judicieux de tester getFuel() y getSpeed() puisqu'ils ne peuvent que retourner 0 (il n'y a pas de setters).

Cependant, en supposant que ce n'était qu'un exemple simplifié à des fins d'illustration, et que vous avez des raisons légitimes de tester les méthodes de la classe de base abstraite (d'autres ont déjà souligné les implications), vous pourriez configurer votre code de test de sorte qu'il crée une sous-classe anonyme de la classe de base qui fournit juste des implémentations factices (no-op) pour les méthodes abstraites.

Par exemple, dans votre TestCase vous pourriez faire ça :

c = new Car() {
       void drive() { };
   };

Ensuite, testez le reste des méthodes, par exemple :

public class CarTest extends TestCase
{
    private Car c;

    public void setUp()
    {
        c = new Car() {
            void drive() { };
        };
    }

    public void testGetFuel() 
    {
        assertEquals(c.getFuel(), 0);
    }

    [...]
}

(Cet exemple est basé sur la syntaxe de JUnit3. Pour JUnit4, le code serait légèrement différent, mais l'idée est la même).

1 votes

Merci pour la réponse. Oui, mon exemple était simplifié (et pas très bon). Après avoir lu toutes les réponses ici, j'ai écrit une classe factice. Mais comme l'a écrit @nsfyn55 dans sa réponse, j'ai écrit un test pour chaque descendant de cette classe abstraite.

0 votes

C'est la meilleure réponse.

2voto

Kamil Points 270

Utilisez le mocking. Consultez Mockito par exemple.

0voto

Vous ne pouvez pas tester toute la classe abstraite. Dans ce cas, vous avez des méthodes abstraites, ce qui signifie qu'elles doivent être implémentées par les classes qui étendent la classe abstraite donnée.

Dans cette classe, le programmeur doit écrire le code source qui est dédié à sa logique.

En d'autres termes, il n'y a aucun sens à tester une classe abstraite car vous n'êtes pas en mesure de vérifier son comportement final.

Si vous avez une fonctionnalité majeure non liée aux méthodes abstraites dans une classe abstraite, il suffit de créer une autre classe dans laquelle la méthode abstraite lèvera une exception.

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