Question

J'ai récemment commencé à utiliser des outils de couverture de code (notamment Emma et EclEmma), et j'aime beaucoup le point de vue qu'il me donne quant à la complétude de mes tests unitaires - et à la possibilité de voir quels domaines du code mon unité les tests ne frappent pas du tout. Je travaille actuellement dans une organisation qui ne fait pas beaucoup de tests unitaires, et je compte bien pousser tout le monde à prendre en charge les tests unitaires, la couverture de code et le TDD et, espérons-le, à convertir l'organisation.

Je ne suis pas sûr du problème avec ce sujet, mais à quel point je devrais utiliser la couverture de mon code. Par exemple, si j'ai une classe comme celle-ci:

//this class is meant as a pseudo-enum - I'm stuck on Java 1.4 for time being
public final class BillingUnit {

    public final static BillingUnit MONTH = new BillingUnit("month");
    public final static BillingUnit YEAR = new BillingUnit("year");

    private String value;

    private BillingUnit(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    public boolean equals(Object obj) {
        return value.equals(((BillingUnit) obj).getValue());

    }

    public int hashCode() {
        return value.hashCode();
    }
}

J'ai écrit quelques tests unitaires simples pour vérifier que equals () fonctionne correctement, que getValue () renvoie ce que j'attendais, etc. Mais, grâce à la nature visuelle d’EclEmma, ??la méthode hashcode () s’affiche en rouge vif pour "non testé".

Vaut-il la peine de tester hashCode () , dans cet exemple, compte tenu de la simplicité de sa mise en oeuvre? Je pense que j'ajouterais un test unitaire pour cette méthode simplement pour augmenter la couverture de code% et me débarrasser de la mise en évidence rouge éclatante qu'EclEmma ajoute à ces lignes.

Peut-être que je suis névrosé et que je ressemble à un TOC, mais je trouve qu'utiliser quelque chose comme EclEmma qui permet de voir si facilement ce qui n'a pas été testé - le plugin met en évidence le code source en rouge et le code couvert en vert - rend vraiment Je veux faire en sorte que 100 classes soient aussi vertes que possible, même si cela n’apporte pas un avantage considérable.

Était-ce utile?

La solution

J'utilise la couverture de code pour me donner des astuces sur les endroits où mes tests peuvent être incomplets. Par exemple, je peux écrire un test pour une fonctionnalité donnée, puis développer le code qui satisfait cette fonctionnalité, mais ce faisant, écrivez du code qui en fait plus que ce qu'il est censé faire - par exemple, il peut intercepter une exception dans un autre cas. que le test n'exerce pas. Lorsque j'utilise l'analyseur de couverture, je constate que j'ai introduit du code sans test associé. Cela m'aide à savoir si je n'ai pas écrit assez de tests.

D'autre part, l'analyse de la couverture peut conduire à une fausse sécurité. Avoir tout votre code couvert ne signifie pas que vous avez assez de tests. Vous devez penser aux tests du point de vue de ce que le code devrait faire et écrire des tests pour vous en assurer. De préférence en écrivant le test en premier. Le fait que votre code soit complètement recouvert ne signifie pas qu’il fait ce qu’il est censé faire.

Dans votre exemple, j'aurais écrit le test de hashCode pour définir le fonctionnement de la fonctionnalité de la méthode avant d'écrire le code. Par conséquent, je l'aurais couvert. Cela ne signifie pas que j'ai toujours une couverture de 100%. Je ne suis pas trop zélé pour écrire des tests pour des accesseurs simples, par exemple. Je ne peux pas non plus tester les méthodes de la classe parente où j'hérite d'un framework, car je ne ressens pas le besoin de tester le code d'autres personnes.

Autres conseils

Je pense qu'il est intéressant d'utiliser une bibliothèque où vous pouvez choisir d'ignorer certains types d'énoncés. Par exemple, si vous avez beaucoup de:

if(logger.isDebugEnabled()) {
    logger.debug("something");
}

Il est utile de pouvoir désactiver les calculs de couverture pour ce type de lignes. Il peut également être (sans doute) valable de désactiver les calculs de couverture pour les getters et les setters triviaux (ceux qui simplement définissent ou renvoient une variable membre sans autre contrôle ni effet secondaire). Je pense cependant que si vous avez remplacé les égaux et hashcode, ceux-ci devraient être testés. Vous avez ajouté une fonctionnalité non triviale, et il convient de la tester.

Pour être clair, la raison pour laquelle je pense que les situations ci-dessus devraient être exclues de la couverture est la suivante:

  • Ne pas tester cette fonctionnalité est ok. Vous ne devriez pas avoir à exécuter votre suite complète de tests 5 fois, avec la bibliothèque de journalisation définie sur chaque niveau de journalisation, juste pour vous assurer que toutes vos instructions sont consultées.
  • Si vous agissiez ainsi, votre couverture serait faussée dans l'autre sens. Si 90% de vos branches sont si (log.isDebugEnabled ()) , et que vous les testez toutes mais pas d'autres branches, vous aurez l'air d'avoir une couverture de 90% des branches (bonne), alors qu'en réalité , vous avez 0% de couverture de branche non triviale (mauvais !!).

Il existe une différence entre la couverture de code et la couverture de test. Vous devez essayer de vous assurer que votre code est correctement testé au lieu d’avoir une couverture à 100%.

Considérez le code suivant:

public float reciprocal (float ex)
{
    return (1.0 / ex) ;
}

Si vous avez exécuté un test avec une valeur de 1,0, vous obtiendrez une couverture de code à 100% (branche et instruction) avec tous les tests. Le code a évidemment un défaut.

Mesurer la couverture des tests est plus difficile et consiste à devenir un meilleur développeur et testeur.

En ce qui concerne plus particulièrement hashCode, un vrai dirait que vous devriez avoir un test unitaire séparé pour cette méthode. Je veillerais personnellement à l'inclure dans au moins un test d'intégration d'unité et à ne pas tester directement chaque accesseur / modificateur. Le retour sur investissement est souvent trop faible pour justifier l'effort. En supposant bien sûr que vous disposiez d’un test unitaire garantissant la génération du code de hachage correct.

Atteindre une couverture de code à 100% avec des tests significatifs peut ne pas valoir l’ascension et, comme mentionné précédemment, une couverture de code à 100% ne signifie pas nécessairement que toutes les conditions possibles de l’application ont été remplies. testé.

Comme pour tester est égal à , hashCode et quelques autres interfaces basées sur un contrat , comme Comparable et Serializable , j'inclus ces tests. Il est important que le contrat equals / hashCode soit correctement implémenté, de même que equals / Comparable .

Voir JUnit-Addons , en particulier

Cela n’est peut-être pas trop compliqué maintenant, mais une simple vérification visant à vérifier qu’il fonctionne toujours comme prévu peut être très utile ultérieurement si la méthode est modifiée.

Puisque le chèque devrait être très facile à écrire, pourquoi ne pas le faire? Cela aide les statistiques et vous permet également de vérifier plus tard, juste au cas où ça casse.

En outre, pour le TDD, vous souhaitez une couverture à 100%, car vous pouvez alors être sûr (ou très proche de cela) que vous ne cassez rien lorsque vous refactorisez.

Un collègue programmeur est resté comme moi dans l'ancien Java1.4;)

Comme indiqué dans mon précédent répondre , le code couvert n'est pas un test de code. Et la conclusion est la suivante: à partir d’un moment donné, le seul moyen d’améliorer la couverture de code est de… supprimer le code!

Maintenant, en ce qui concerne hashCode, il est intéressant de l’inscrire dans une conception de test unitaire pour vérifier que le mécanisme trié attendu est respecté (et non pour couvrir une fonction supplémentaire)

Comme je l'ai dit ailleurs, une faible couverture de code est un problème, mais une couverture de code élevée ne signifie pas que vous écrivez en or pur.

Si la couverture de code ne vous préoccupe pas, alors je vous suggérerais de réaliser des tests pour equals () et getValue () - en fonction de comment et où hashCode () est utilisé (désolé, je suis un développeur C #), vous pourrez peut-être vouloir tester cela.

La partie la plus importante est que vos tests vous garantissent que vous avez écrit le bon code et qu'il fonctionne comme prévu.

Dans ce cas particulier, je dirais que puisque vous testez la méthode equals, vous pouvez également vérifier que des objets identiques ont des codes de hachage égaux: il suffit d'ajouter un test supplémentaire à tous les cas où equals doit renvoyer true. .

Cela vous donnera une couverture de code et vous donnera la certitude que hashCode satisfait réellement son contrat: -)

Cela ne vaut que marginalement, étant donné que vous pouvez évidemment faire confiance à la méthode hashCode de String et que vous ne vous attendez pas à changer cette classe. Mais si vous êtes suffisamment méfiant vis-à-vis de votre méthode equals pour la tester, vous devriez en avoir assez pour vérifier qu'elle et le hashCode restent cohérents. Et vous devriez toujours vous méfier des hypothèses que vous ne voudrez plus, à l'avenir, déconner avec ce que vous avez fait auparavant. Par exemple, si quelqu'un se présente et décide d'optimiser en ajoutant un contrôle d'égalité de pointeur, vous pouvez également disposer d'un ensemble complet de tests pour lui permettre d'exécuter son code modifié. Sinon, ils perdront du temps avec le même souci que vous: avez-vous raison de ne pas avoir la couverture de code?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top