web-dev-qa-db-fra.com

Comment tester les types d'énumération?

J'essaie actuellement de construire un ensemble plus ou moins complet de tests unitaires pour une petite bibliothèque. Puisque nous voulons permettre à différentes implémentations d'exister, nous voulons que cet ensemble de tests soit (a) générique, afin que nous puissions le réutiliser pour tester les différentes implémentations et (b) aussi complet que possible. Pour la partie (b), j'aimerais savoir s'il existe des meilleures pratiques pour tester les types d'énumération. Ainsi, par exemple, j'ai une énumération comme suit:

public enum Month {
    January,
    February,
    ...
    December;
}

Ici, je veux m'assurer que tous les types d'énumération existent vraiment. Est-ce même nécessaire? Actuellement, j'utilise Hamcrests assertThat comme dans l'exemple suivant:

assertThat(Month.January, is(notNullValue()));

Une énumération "janvier" manquante entraînerait une erreur de temps de compilation que l'on peut corriger en créant le type d'énumération manquant.

J'utilise Java ici, mais cela ne me dérange pas si votre réponse est pour une langue différente ..

Modifier:

Comme mkato et Mark Heath l'ont souligné, les tests d'énumérations peuvent ne pas être nécessaires car le compilateur ne compilera pas lorsque vous utilisez un type d'énumération qui n'est pas là. Mais je veux toujours tester ces énumérations car nous voulons construire un test.jar séparé de type TCK qui exécutera le même test sur différentes implémentations. Donc ma question était plutôt censée être: Quelle est la meilleure façon de tester les types d'énumération?

Après y avoir réfléchi un peu plus, j'ai changé la déclaration Hamcrest ci-dessus en:

assertThat(Month.valueOf("January"), is(notNullValue()));

Cette déclaration lance désormais un NPE lorsque janvier n'est pas (encore) là. Y a-t-il un problème avec cette approche?

17
seb

Pour les énumérations, je les teste uniquement lorsqu'elles contiennent des méthodes. Si c'est une énumération de valeur pure comme votre exemple, je dirais ne vous embêtez pas.

Mais comme vous avez envie de le tester, opter pour votre deuxième option est bien meilleur que le premier. Le problème avec le premier est que si vous utilisez un IDE, tout changement de nom sur les énumérations renommerait également ceux de votre classe de test.

21
aberrant80

Je suis d'accord avec aberrant8 .

Pour les énumérations, je les teste uniquement lorsqu'elles contiennent des méthodes. Si c'est une énumération de valeur pure comme votre exemple, je dirais ne vous embêtez pas.

Mais comme vous avez envie de le tester, opter pour votre deuxième option est bien meilleur que le premier. Le problème avec le premier est que si vous utilisez un IDE, tout changement de nom sur les énumérations renommerait également ceux de votre classe de test.

Je voudrais développer cela en ajoutant que les tests unitaires un Enum peuvent être très utiles. Si vous travaillez dans une grande base de code, le temps de construction commence à monter et un test unitaire peut être un moyen plus rapide de vérifier la fonctionnalité (les tests ne construisent que leurs dépendances). Un autre gros avantage est que les autres développeurs ne peuvent pas modifier involontairement les fonctionnalités de votre code (un gros problème avec de très grandes équipes).

Et avec tout le développement piloté par les tests, les tests autour d'une méthode Enums réduisent le nombre de bogues dans votre base de code.

Exemple simple

public enum Multiplier {
    DOUBLE(2.0),
    TRIPLE(3.0);

    private final double multiplier;

    Multiplier(double multiplier) {
        this.multiplier = multiplier;
    }

    Double applyMultiplier(Double value) {
        return multiplier * value;
    }

}

public class MultiplierTest {

    @Test
    public void should() {
        assertThat(Multiplier.DOUBLE.applyMultiplier(1.0), is(2.0));
        assertThat(Multiplier.TRIPLE.applyMultiplier(1.0), is(3.0));
    }
}
9
Mike Rylander

vous pouvez tester si vous avez exactement certaines valeurs, par exemple:

for(MyBoolean b : MyBoolean.values()) {
    switch(b) {
    case TRUE:
        break;
    case FALSE:
        break;
    default:
        throw new IllegalArgumentException(b.toString());
}

for(String s : new String[]{"TRUE", "FALSE" }) {
    MyBoolean.valueOf(s);
}

Si quelqu'un supprime ou ajoute une valeur, une partie du test échoue.

4
razzek

Habituellement, je dirais que c'est exagéré, mais il y a parfois des raisons d'écrire des tests unitaires pour les énumérations.

Parfois, les valeurs affectées aux membres d'énumération ne doivent jamais changer ou le chargement des données persistantes héritées échouera. De même, les membres apparemment inutilisés ne doivent pas être supprimés. Les tests unitaires peuvent être utilisés pour éviter qu'un développeur n'apporte des modifications sans en réaliser les implications.

4
Mark Heath

Si vous utilisez tous les mois dans votre code, votre IDE ne vous permettra pas de compiler, donc je pense que vous n'avez pas besoin de tests unitaires.

Mais si vous les utilisez avec réflexion, même si vous supprimez un mois, il sera compilé, il est donc valide de mettre un test unitaire.

3
mkato