Construire une couverture de test unitaire de rupture. Oh, tu n’es pas dedans ? L’avez-vous déjà essayé? Vous pourriez être ennuyé que j’essaie même d’en parler. Faisons juste fondre ce visage fondant
Les tests unitaires ont pour principal avantage de garantir que notre code se comporte comme nous le disons. C’est aussi une forme efficace de documentation, nous donnant la confiance nécessaire pour améliorer notre base de code grâce à la refactorisation. Même avec tous ces avantages, les meilleurs développeurs sont susceptibles de lésiner sur leur écriture lorsqu’il n’y a pas de pénalité immédiate. Nous allons parcourir l’introduction d’outils pour échouer la construction lorsque les objectifs de couverture ne sont pas à la hauteur d’une manière qui apporte une pure joie.
Notre point de départ est que nous avons une version d’intégration continue (CI) qui s’exécute python -m unittest discover
comme couvert dans les docs. Commencer à mesurer la couverture des tests d’unités est aussi simple que pip install coverage
en Python (plus d’infos). Si vous avez un script Python pour exécuter des tests, nous collecterons des données de couverture en exécutant ce qui suit :
def run_tests():
""" Run the unit tests, collect coverage data and output an xml report.
Adjust the cwd to match your test root folder.
"""
subprocess.check_call(
[
"coverage",
"run",
"-m",
"unittest",
"discover",
],
cwd="test",
)
subprocess.check_call(["coverage", "xml"], cwd="test")
Pour voir un bon rapport HTML, utilisez le code suivant :
def open_html_coverage_report():
subprocess.check_call(
["coverage", "html", "-d", "_coverage_data"], cwd="test"
)
subprocess.check_call(["open", "_coverage_data/index.html"], cwd="test")
Une fois que vous avez pris le temps d’explorer le rapport et de développer une image de votre couverture actuelle, nous prenons les premières mesures pour établir la loi. Mais de la manière la plus gentille et la plus douce.
def check_coverage():
""" Generate a coverage report and fail if minimum coverage is not met.
"""
subprocess.check_call(["coverage", "xml", "--fail-under=85"], cwd="test")
Vous regardez maintenant l’un des deux résultats suivants :
Dans le premier scénario, tout s’est déroulé avec succès. S’il s’agit d’un tout nouveau projet et que vous installez la clôture avant d’adopter le chiot, félicitations ! L’ajout de cette vérification à un projet entièrement nouveau est la solution la moins douloureuse. Il peut également arriver que vous ayez, par hasard, un niveau élevé de couverture sur un projet sans aucun rapport en place, mais woooo, ce n’est pas probable.
Dans le deuxième scénario, un message comme celui-ci s’affiche :
Coverage failure: total of 56 is less than fail-under=85
Personne n’est fou. Les coups ne continueront pas tant que la couverture ne s’améliorera pas. Nous allons faire la chose la plus humaine possible. Acceptation. Définissez simplement le seuil pour qu’il corresponde au niveau de couverture actuel. C’est ça. Vraiment. Même si vous ne faites rien d’autre, faire respecter à chaque pull request que vous ne laisserez pas le niveau de couverture se détériorer est un grand pas en avant. Et vous n’avez plus besoin de hausser les épaules lorsqu’on vous demande quelle est votre couverture de test unitaire.
Maintenant, vous avez les commandes pour câbler vos tests locaux pour exécuter les tests avec des données de couverture et pour vérifier par rapport à la cible. Exécutez cette même commande dans votre CI, et je suis heureux de vous dire au revoir. Mais si tu veux sortir, j’ai encore quelques trucs pour Jenkins.
Jusqu’à présent, notre travail comprend la génération de données de couverture au format XML que le plug-in Cobertura utilisera pour produire un beau rapport dans l’interface utilisateur Jenkins et définir l’état de la construction. Commencez par installer le plugin si vous ne l’avez pas déjà. Voici le lien : https://plugins.jenkins.io/cobertura/
Avant de sauter dans le Jenkinsfile
, il faut être clair. Vous voulez que vos scripts aient une commande de test locale qui utilise le --fail-under
paramètre et une commande de test CI qui ne l’inclut pas. Sur Jenkins, nous voulons toujours produire le rapport XML et exécuter l’étape de cobertura. Le plugin Cobertura vérifiera le niveau de couverture et échouera la construction (docs).
Voici à quoi ressemblera notre fichier Jenkins après avoir exécuté les tests :
cobertura autoUpdateHealth: false,
autoUpdateStability: false,
coberturaReportFile: '**/test/coverage.xml',
conditionalCoverageTargets: '70, 0, 0',
failUnhealthy: false,
failUnstable: true,
lineCoverageTargets: '80, 0, 85',
maxNumberOfBuilds: 0,
methodCoverageTargets: '80, 0, 0',
onlyStable: false,
sourceEncoding: 'ASCII',
zoomCoverageChart: false
Nous allons passer en revue les trois paramètres les plus importants :
coberturaReportFile
doit correspondre à l’emplacement où les données de couverture XML sont enregistrées par lecoverage
commande.failUnstable
marque la construction comme instable lorsqu’elle est inférieure au seuil. Je préfère considérer une construction saine si elle échoue à se construire et instable si elle se construit mais échoue à une étape post-construction.lineCoverageTargets
contient trois nombres, le troisième étant notre cible. Vous pouvez plonger plus profondément dans d’autres couvertures, telles que les conditionnels, mais je vous laisse explorer cela.
Nous avons maintenant une version CI qui échouera si notre seuil de couverture n’est pas atteint ! Je limiterai la portée de cet article à ce jalon. Idéalement, votre système de contrôle de source est déjà configuré pour exécuter le CI lors de l’ouverture d’une demande d’extraction et du blocage des fusions en fonction des résultats, et cela s’intègre parfaitement dans ce flux.
A partir de là, l’équipe doit accepter de réaliser l’esprit de ce contrôle qualité. Pour être totalement efficace, tout le monde est responsable dans le processus d’examen de toujours pousser à élever l’objectif plus haut et de le faire chaque fois que possible. Personne n’est autorisé à le baisser. Tous les cours ou fichiers à sauter sont soigneusement examinés et acceptés. Enfin, les tests de mauvaise qualité sont appelés.
Qu’est-ce qu’une bonne cible ? Sans aucun doute, c’est un sujet profond, mais je vais le traverser avec une expérience pratique. C’est 85 %. Avec les projets qui commencent par une couverture et ceux qui l’ont introduite des années plus tard, 85 % est raisonnable, dégagé et utile. Une couverture plus élevée est réalisable mais généralement dénuée de sens. Chaque projet contient un code passe-partout et un code simple et difficile à tester qui offre peu ou pas de valeur. 85 % permet cela sans avoir à créer de filtres explicites.
Nous avons parcouru les étapes pour introduire des seuils de couverture dans les constructions locales et notre système CI pour maintenir et améliorer en douceur la qualité de vos projets. Vous ne faites pas que bien; Tu t’en sors bien. Comme Superman.