
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.
Utilisez le test de mutation pour améliorer vos compétences en génie logiciel !
Temps de lecture : 24 minutes
La couverture du code (le pourcentage de code exécuté lors de l'exécution de vos tests) est une excellente mesure. Cependant, la couverture ne vous indique pas la capacité de vos tests à détecter les modifications apportées à votre base de code, tout simplement parce qu'il s'agit d'une mesure quantitative. Si vos tests ne sont pas bien conçus, les changements peuvent passer vos tests unitaires mais casser la production.
Les tests de mutation sont un excellent moyen (très sous-estimé) de quantifier la confiance que vous pouvez accorder à vos tests. Les tests de mutation fonctionnent en modifiant votre code de manière subtile, puis en appliquant vos tests unitaires à ces versions "mutées" de votre code. Si vos tests échouent, tant mieux ! S'ils réussissent... cela signifie que votre test n'était pas assez bon pour détecter ce changement.
Dans cette Video, Max de l'équipe Vonage Developer Experience vous montrera comment démarrer avec les tests de mutation dans n'importe quel langage et comment les intégrer dans votre pipeline CI/CD. Bientôt, la détection du code mutant fera partie intégrante de votre processus d'ingénierie des versions, et vous ne regarderez plus jamais les pingouins de la même façon !
Vous trouverez ci-dessous la transcription de la vidéo, ainsi que quelques liens utiles.
Vous pouvez créer un compte de développeur gratuit auprès de Vonage ici..
Si vous avez des questions, n'hésitez pas à nous contacter sur notre communauté Slack.
Bonjour, je m'appelle Max et je suis défenseur des développeurs chez Vonage. Aujourd'hui, j'aimerais vous parler des tests de mutation. Je vais vous dire comment je l'utilise et comment vous pouvez l'utiliser aussi. Avant de commencer, j'aimerais mentionner brièvement l'entreprise pour laquelle je travaille.
Nous sommes une société qui s'appelle Vonage et nous nous occupons, entre autres, d'API de communication. Une grande partie du code avec lequel je travaille concerne donc des choses telles que envoyer des SMS ou passer des appels vocaux, créer des chats vidéodes choses comme ça. Il y a donc beaucoup de choses liées à la communication. Et si je mentionne cela, c'est parce que j'ai appliqué des tests de mutation à notre code. Je vais vous montrer comment j'ai fait, pourquoi c'était un bon choix pour nous, et je vais vous montrer comment vous pouvez le faire. Mais avant de commencer, j'aimerais vous présenter le véritable protagoniste de cet exposé.
Je suis le locuteur, mais le véritable protagoniste est en fait Henry. Voici Henry. Vous pouvez voir, je l'espère, que c'est un adorable petit pingouin. Et la raison pour laquelle il est le personnage le plus important ici, c'est qu'au fur et à mesure que j'apprenais à utiliser les tests de mutation, j'utilisais Henry comme analogie pour beaucoup de choses. Vous comprendrez pourquoi, car je vais également l'utiliser aujourd'hui pour vous montrer comment les tests de mutation fonctionnent réellement. Avant de commencer, posons quelques bases.
Tout d'abord, j'aimerais que vous réfléchissiez à ceci : avez-vous entendu parler des tests ? Je suppose que si vous avez cliqué sur cette vidéo, si vous regardez ceci, vous savez probablement ce qu'est le test pour les logiciels.
J'aimerais également que vous réfléchissiez à la couverture du code. Il se peut que vous connaissiez ou non la couverture du code. Ne vous inquiétez pas si ce n'est pas le cas, car c'est quelque chose que nous allons certainement mentionner. Il y a aussi les tests de mutation. Vous en avez entendu parler, je suppose, si vous avez vu le titre de cette Video, mais c'est quelque chose de très utile en soi. J'espère qu'à la fin de cette Video, vous en saurez beaucoup plus sur les tests de mutation et que vous vous sentirez à l'aise pour les utiliser vous-même. Si cela vous convient, continuons !
Ce que j'aimerais faire, c'est établir une base de référence. Je voudrais donc évoquer les tests, tout d'abord. En fait, il s'agit juste d'une grande question : pourquoi écrivons-nous des tests unitaires ? Quelles sont les raisons qui nous poussent à écrire des tests pour notre code ? Vous voudrez peut-être faire une pause et y réfléchir vous-même. Peut-être pas. Ce n'est pas grave non plus.
Dans ce cas, je vais vous montrer ce que je pense que cela pourrait impliquer. Et voici ce que j'ai obtenu. Vous pouvez donc les écrire pour prouver que votre code fonctionne. Vous pouvez les écrire pour des raisons de documentation afin d'inspirer confiance dans votre code, pour les tests de régression, pour le remaniement, et pour des raisons de conformité également.
Voici donc toutes les choses qui pourraient vous encourager à écrire un test unitaire. Et c'est super d'avoir ça, c'est super d'avoir un moyen de vérifier que notre code fonctionne. C'est très bien que nous ayons un moyen de documenter et toutes ces choses géniales. Mais il y a aussi un petit problème. Le problème est que vous pouvez commencer avec un petit projet, mais ce projet peut rapidement grandir, et ce qu'il fait peut évoluer au fil du temps. Et alors que vous faites des refactors et des choses comme ça, vous pouvez rater du code, vous pouvez sauter des sections. Vous risquez d'oublier des choses. Il se peut que vous ne testiez plus tout votre code. Et le problème ici est que souvent nous ne surveillons pas nos tests.
Si nous ne surveillons pas nos tests, nous ne savons pas ce qui ne va pas dans le code que nous avons, parce que nous n'avons pas de moyen de le tester, et nous ne savons pas si les tests vont nous aider. J'espère donc que nous pouvons voir quel est le défi à relever. J'aimerais dire que les choses s'améliorent parce que nous avons une couverture de code, n'est-ce pas ? Et si vous n'êtes pas sûr de ce que c'est, je vais vous l'expliquer rapidement. Voici ce que j'en dis : "la part du code source d'un programme qui est exécutée lors de l'exécution de la suite de tests". C'est ainsi que je l'expliquerais.
Mais cessons d'en parler et montrons un exemple concret. Voici l'un des SDK open-source dont je m'occupe. Il s'agit essentiellement d'un SDK Python permettant d'effectuer des appels d'API pour différentes choses. Nous avons une API que je prends en charge dans ce SDK et qui s'appelle notre Messages API. À l'intérieur de cette API, vous pouvez envoyer des messages par SMS, MMS, WhatsApp, Facebook, des choses comme ça - beaucoup de canaux différents. J'ai obtenu le code et j'ai exécuté quelques mesures de couverture de code, de sorte que je puisse voir quelles déclarations dans le code je testais, et quelles déclarations je manquais. Vous pouvez voir ici que j'ai couvert la majeure partie du code, mais qu'il manque une instruction à la ligne 23, qui me dit que je n'ai pas écrit de test pour cette instruction.
Dans ce cas, je n'ai pas essayé ce type d'authentification. Je peux donc écrire un test pour ce type d'authentification. Ainsi, la couverture de code a déjà amélioré mon code, et c'est génial ! Que peut-il faire d'autre ?
Il peut en fait vous donner une vue d'ensemble de votre projet et de toutes les différentes déclarations qu'il contient - en gros, le niveau de couverture que vous avez. Voici donc à quoi cela ressemble pour moi. Et cela me semble très bien. Il y a vraiment un grand potentiel ici parce que tout d'abord, cela vous permet d'écrire plus de tests et de meilleurs tests.
Il est également très facile et peu coûteux de mesurer ces éléments. Il n'est pas très compliqué de calculer la couverture du code et de dire " qu'est-ce que j'ai couvert " ? L'autre bonne chose, la meilleure, c'est qu'elle montre ce que vous n'avez pas testé et donc vous savez, hé, je dois faire attention à cela. Si je ne fais pas confiance à ce code, ce qui est souvent le cas. C'est très utile. La couverture du code couvre donc beaucoup de choses.
En fait, je pense que nous avons peut-être terminé, merci beaucoup. J'ai été ravi de parler avec vous aujourd'hui. Je vous reverrai... sauf qu'en fait, il y a des choses qui ne sont pas très bonnes.
Tout d'abord, la couverture du code peut être un peu trompeuse. Elle ne garantit pas non plus la qualité de vos tests. Ce que je vais faire, c'est vous montrer un exemple de code Python très simple, le voici. Et tout ce que je fais ici, c'est importer le module requests c'est-à-dire la bibliothèque que j'utilise.
Ensuite, je fais un appel API avec cette bibliothèque. Tout ce que je fais, c'est une requête GET à une URL spécifique, puis je reçois la réponse et je renvoie le JSON de la réponse à l'utilisateur. Et c'est très bien. Tout va bien. Nous pouvons voir sur la diapositive suivante, la page suivante, ce que j'ai ici, c'est un test pour cela.
La couverture est en fait de 100 %, mais ce n'est pas très utile. Nous pouvons voir ici que nous avons quelque chose qui appelle l'API. Mais ce qu'il fait en réalité, c'est appeler l'API et se contenter de dire que si je l'ai appelée, c'est bon. Donc, si ce code s'est exécuté, c'est bon. Mais cela ne permet pas de valider les éléments qui pourraient revenir.
Il se peut que nous recevions une réponse de 200. Nous pourrions recevoir une réponse de 400. Il se peut que nous recevions autre chose. Nous pourrions obtenir quelque chose que nous n'attendons pas, et nous ne gérons aucun de ces cas. Et nous ne testons aucun de ces cas non plus. En fait, ce test n'est pas très utile pour vous aider.
J'aimerais donc vous poser rapidement une question : avez-vous déjà écrit un morceau de code, puis un test, non pas parce que ce test allait être utile, mais parce que vous aviez besoin d'augmenter un peu la couverture de votre code. Je l'ai fait et beaucoup de gens l'ont fait aussi. Si vous ne l'avez pas fait, tant mieux, je suis fier de vous, mais en réalité, la plupart d'entre nous ont fait ce genre de choses.
Ce qui se passe souvent avec la couverture du code, c'est que nous finissons par en faire un objectif plutôt que quelque chose qui est censé nous donner des informations. Il s'agit en fait d'un principe qui porte un nom. C'est une chose réelle, et elle s'appelle la loi de Goodhart. Elle ne s'applique pas uniquement à la couverture des tests, mais l'énoncé est essentiellement le suivant : "Lorsqu'une mesure devient une cible, elle cesse d'être une bonne mesure".
C'est très important et je le répète : "Lorsqu'une mesure devient un objectif, elle cesse d'être une bonne mesure". Qu'est-ce que je veux dire par là ? Eh bien, ce que je veux dire, c'est que nous avons pris la couverture du code, qui est censée nous renseigner sur notre code et nos tests et sur la façon dont ils fonctionnent, mais en fait nous l'avons transformée en un chiffre que nous nous soucions d'optimiser.
Ainsi, au lieu de penser à faire de meilleurs tests, nous pensons à optimiser un nombre, ce qui n'est pas aussi bon. Cela nous amène à nous poser certaines questions. Par exemple, comment pouvons-nous comprendre ce que font réellement nos tests ? Comment savoir si nos tests sont fiables ? En fait, la meilleure réponse à cette question a été trouvée vers l'an 100 par le penseur romain Juvénal (après un quatrième verre de vin), et la réponse qu'il a trouvée était "Qui surveille les surveillants ? Qui s'occupe des gens qui devraient s'occuper de nous ? Et de la même manière, qui teste nos tests ?
J'affirme avoir une réponse pour vous aujourd'hui, et j'affirme que la réponse est le test de mutation. Vous avez peut-être remarqué qu'Henry a fait sa réapparition.
Et c'est génial parce que tout d'abord, il est adorable, mais plus important encore, il va nous aider maintenant. L'année dernière, lorsque j'ai commencé à me familiariser avec les tests de mutation, j'ai beaucoup réfléchi à la façon dont je pourrais les appliquer à mon code, et je me suis demandé comment conceptualiser et comprendre cela pour moi-même. J'ai imaginé que mon code, qui envoie de nombreux appels API et traite des appels API et des messages, était comme un pigeon ou une colombe, comme un oiseau qui peut voler. Dans cette analogie, je peux attacher un message à la patte de l'oiseau et le laisser s'envoler pour qu'il délivre mon message.
Il s'envolera donc et fera ce que je veux qu'il fasse. Le problème avec les pingouins, c'est qu'ils sont des oiseaux, donc ils répondent à ces critères, mais ils ne peuvent pas voler, comme vous le savez sans doute, et cela les met en colère. Mais plus important encore, un mutant de cette manière est comme un oiseau normal transformé en pingouin qui ne peut plus faire cette chose centrale dont j'ai besoin, c'est-à-dire que l'oiseau vole. Voyons un exemple concret en utilisant des images d'oiseaux, car c'est ce que nous faisons aujourd'hui.
Tout d'abord, nous commençons par un code de production, qui fonctionne comme prévu. Ensuite, nous effectuons une sorte d'opération de mutation et créons une version mutante de ce code. Nous avons donc, par exemple, cette fonction, qui est Python. Elle ajoute simplement deux nombres et renvoie la somme de ces deux nombres. Maintenant, une version mutante de cette fonction pourrait, par exemple, soustraire des nombres ou ajouter une constante, ou renvoyer l'addition de deux chaînes de caractères, des choses comme ça.
Il peut ne rien renvoyer du tout, ou toute sorte d'opération logique qui peut changer ce que cette ligne de code renvoie. Que faisons-nous donc avec les tests de mutation ? Nous avons créé quelques mutants, que faisons-nous ensuite ?
Je prends les mutants que nous avons. Je les appelle les Fab 4 pour des raisons qui devraient être évidentes, et ce que nous devons faire, c'est les confronter à notre suite de tests. Nous prenons donc chaque mutant. Et ce que nous faisons essentiellement dans cette analogie, c'est de voir si ce mutant peut voler, s'il peut passer le test dont il a besoin pour pouvoir s'envoler et porter ce message. Henry, notre beau pingouin mutant, doit donc essayer de voler.
Ainsi, lorsque nous prenons ce mutant, nous exécutons nos suites de tests. Et dans le meilleur des cas, nos tests vont échouer. C'est une bonne chose car cela signifie que nous avons révélé Henry pour ce qu'il est, c'est-à-dire un adorable pingouin, ce qui est génial, car cela signifie que nous n'allons pas le laisser passer en production. Nous l'avons attrapé dans nos tests. Maintenant, si les tests passent, ce n'est pas le bon moment parce que ce qui s'est passé, c'est que nous n'avons pas remarqué qu'Henry est un pingouin et non un pigeon.
Et il est capable de voler. Regardez ces ailes, ce pingouin peut soulever un bus, n'est-ce pas ? Très impressionnant. Mais cela signifie que ce mutant pourrait entrer dans la production, et c'est ce que nous ne voulons pas. Alors qu'est-ce que ça nous apporte ?
Et j'affirme que cela nous donne un moyen d'évaluer la qualité de nos tests. C'est ce que sont les tests de mutation.
Parlons de quelques frameworks auxquels vous pourriez penser. Avec les frameworks, il y a différentes options pour différents langages, vous savez, chaque langage a une version de cela. Dans mon cas, j'utilise mutmut, qui est un framework de test de mutation basé sur Python.
Mais si vous vous intéressez à d'autres langages, il existe des logiciels comme Pitest pour Java ou Stryker pour JavaScript, C#, etc. Il existe donc des options pour de nombreux langages. Et si la langue n'a pas été mentionnée, il y a probablement quelque chose pour elle. Je ne suis ni médecin, ni conseiller financier, ni enseignant, ni quoi que ce soit de ce genre - la valeur de votre investissement peut varier à la hausse comme à la baisse. Mais le plus important pour moi, c'est que ce que j'ai utilisé est ce dont je vais parler.
Je vais donc parler de mutmut aujourd'hui parce que c'est ce que j'ai utilisé moi-même. Et ce que j'ai fait, c'est appliquer ce test de mutation à mon propre SDK, et je vais vous montrer comment je l'ai fait maintenant. Tout d'abord, je pip install mutmutqui est juste une façon Pythonique d'installer des choses, puis je l'exécute. C'est tout.
Heureusement, il comporte des paramètres par défaut judicieux, que je n'ai pas eu besoin de modifier. Il se peut que vous deviez changer ce qu'il y a là en fonction de ce que vous faites. Il y a différentes options de configuration que vous pouvez choisir, mais pour moi, c'était parfait. Lorsque j'ai exécuté ce programme, il m'a indiqué ce qui allait se passer. Il a imprimé ceci.
Il a imprimé le fait qu'il allait exécuter toute la suite de tests, tout d'abord pour comprendre le timing et d'autres choses de ce genre. Ensuite, il a généré les mutants et les a vérifiés. Il y a donc différents résultats possibles. Par exemple, nous pouvons attraper un mutant, nous pouvons avoir un mutant qui s'arrête, ce qui n'est pas bon, nous pouvons avoir des mutants qui semblent suspects et auxquels nous ne faisons peut-être pas confiance, et nous pouvons aussi avoir des mutants qui ont survécu. Et dans ce cas, c'est une très mauvaise situation où nous savons que nous n'avons pas attrapé ce mutant. Donc, quand j'ai exécuté ceci, ce que nous avons vu tout d'abord, c'est qu'il a exécuté ma suite de tests et ensuite il a vérifié ces mutants et il a pu voir que j'en ai attrapé 512, mais il n'en a pas attrapé 170. Réfléchissez-y.
S'agit-il d'un bon ou d'un mauvais chiffre ? Nous en reparlerons plus tard, mais pour l'instant, examinons quelques mutants. Voici un mutant simple que nous pouvons attraper. Nous avons commencé avec ceci. Il s'agit de notre classe Messages API.
Nous avons des canaux de messages valides par lesquels nous pouvons envoyer des messages. Et le mutant vient juste de changer l'un d'entre eux. Il a modifié l'une des chaînes de caractères. Nous ne pouvions donc plus envoyer de messages par SMS. Lorsque nous avons fait un test pour cela, il a échoué, et c'est très bien.
Cela signifie que nous appelons cela. En voici une autre. Je ne sais pas si les personnes qui nous regardent ont utilisé Pydantic, mais Pydantic est une excellente bibliothèque de validation, et nous l'utilisons dans le SDK. Voici un exemple où nous avons un validateur, c'est Pydantic V1, c'est quelque chose qui arrondit un nombre. Mais la version mutée a supprimé cette annotation, ce décorateur (selon votre langue, vous l'appellerez différemment, nous les appelons décorateurs en Python).
Nous l'avons donc supprimé. Et cela signifiait que ce code ne serait jamais appelé, donc quand j'avais un test pour arrondir un nombre, il n'aurait jamais été appelé. Et donc cela a échoué aussi. C'est une bonne chose car cela signifie qu'il y a deux versions de la base de code, deux petits Henries que nous avons pu attraper et dire, hey, vous êtes un pingouin, ce qui est ce dont nous avons besoin.
Comment voit-on les mutants ? Eh bien, si vous faites mutmut showil peut vous en donner une liste. Et vous pouvez, par exemple, nommer 1, comme montrer le numéro 1, montrer le premier mutant et vous êtes en mesure de le voir. Dans notre cas, le numéro 1 ici, par exemple, change le type d'authentification et, bien sûr, il était facile de l'attraper. Mais ce qui est vraiment intéressant, c'est que nous pouvons voir les résultats de tous ces tests.
Nous avons donc un rapport au format HTML. Selon votre langue et le logiciel de test de mutation que vous utilisez, il sera plus ou moins facile de faire cela. Pour nous, il s'agit d'une interface assez simple, mais ce qu'elle fait essentiellement, c'est qu'elle vous montre tous les mutants que vous n'avez pas attrapés dans chaque fichier. Regardons-en quelques-uns.
Voici le mutant 58, que nous n'avons pas attrapé, et vous verrez qu'ils ne sont pas tous égaux. Donc ce mutant, vous pouvez voir que tout ce que nous avons fait ici est de renommer le logger. Et je pense que la journalisation n'entre pas dans le cadre de mes tests. Et donc pour mon argent, ça ne me dérange pas que ce mutant soit entré, c'est bon parce que je ne pense pas que c'est ce que je devrais tester.
Ce n'est donc pas grave. Voici un autre exemple. Voici le mutant 62. Et à l'intérieur, tout ce que nous faisons, c'est changer la valeur d'une constante. Et, encore une fois, je ne pense pas que cela entre dans le cadre de ce que je veux tester.
Je ne pense pas qu'il soit important pour moi de tester si une valeur par défaut est définie ou non. Ce n'est pas important pour moi dans ce contexte. Mais examinons-en un qui est plus important, qui m'intéresse. En voici une. Il s'agit du mutant 112.
Et ce que je fais ici, c'est que je crée des instances de toutes les classes pour toutes les API que nous utilisons. Vous pouvez voir ici que nous avons une classe de voix. Dans la version mutante, nous ne créons pas de classe voice, mais nos tests passent toujours, même si nous ne créons pas de classe pour toutes nos méthodes voice. Pourquoi cela se produit-il ?
Pourquoi mes tests n'échouent-ils pas ? Qu'est-ce qui se passe ? Eh bien, il s'avère que la façon dont nous utilisons ceci et la façon dont nous testons dans le SDK est que nous n'appelons pas simplement à travers les objets du client. En fait, nous appelons directement la classe Voice API, mais nos utilisateurs l'appelleront comme ceci. Et donc, en fait, je devrais probablement avoir un test pour cela.
Celui-ci m'indique donc quelque chose de très important à propos de mon code qui améliorera la qualité des tests parce que je peux écrire un test pour ce cas précis, qui est représentatif de ce que nos utilisateurs feront. Revenons donc à ce chiffre. Nous avons attrapé beaucoup de mutants. Nous n'avons pas non plus attrapé beaucoup de mutants. En fait, nous n'avons attrapé qu'environ 75 % de ces mutants.
En fait, nous avons raté environ 25 %. La question que je me pose est la suivante : est-ce un bon chiffre ? 75%. Est-ce que c'est bon ? Et si vous regardez ceci et haussez les épaules, c'est la bonne réponse.
Ce qui est intéressant ici, c'est que 100 % n'a pas de sens ! Parce qu'il y a des cas dont je ne me soucie pas, n'est-ce pas ? Comme l'enregistreur ou la constante qui change. Je ne m'en soucie pas. Ce que j'utilise, ce n'est pas pour obtenir une couverture de mutation de 100%, parce qu'alors tout ce que j'ai fait, c'est prendre le problème du score de couverture de code et l'abstraire à nouveau. Ce qui m'importe vraiment, c'est d'avoir un bon aperçu de mon code, c'est ce qui m'importe vraiment.
J'espère vous avoir convaincu que vous pourriez vouloir explorer un peu les tests de mutation vous-même. Mais si ce n'est pas le cas, ne vous inquiétez pas car ce que je vais faire maintenant, c'est vous montrer comment vous pouvez commencer avec les tests de mutation, et c'est tellement simple qu'en fait, je pense que n'importe qui peut le faire si vous écrivez déjà des tests. Tout d'abord, quelques conseils généraux : commencez localement, exécutez d'abord sur votre machine. C'est ce que j'ai fait. Je l'ai exécuté localement sur ma machine. Commencez petit. Si vous avez une base de tests plus importante que la mienne, si vous avez un ensemble de tests plus important, vous pouvez commencer par un sous-ensemble de ces tests. Vous voudrez peut-être aussi ajuster les performances. Vous voudrez peut-être exclure des tests spécifiques qui ne vous concernent pas. Par exemple, les tests d'intégration ne vous intéressent pas tant que cela.
Vous pouvez aussi vouloir exclure certaines parties du code, par exemple, si vous avez généré du code automatiquement, vous ne vous en souciez probablement pas.
Lorsque vous voudrez vous débarrasser de votre machine, ce qui n'est pas impossible, cette partie vous sera d'une grande utilité. Tout d'abord, je suis très heureux de cette image de pingouin. Je ne sais pas pourquoi elle existe de cette façon, mais je suis très heureux qu'elle existe.
Mais pourquoi voudriez-vous vous débarrasser de votre machine ? Je vais vous le dire. Les tests prennent du temps. Vous pourriez vouloir utiliser les ressources du cloud plutôt que d'utiliser votre propre machine lorsque vous voulez exécuter une suite de tests. Cela signifie également que vous pouvez l'ajouter à votre système CI, ce qui est très utile.
Cela signifie que vous pouvez spécifier les différentes plates-formes sur lesquelles vous voulez travailler, les différents systèmes d'exploitation, les différentes versions de votre langage, les différentes versions de votre code. Laissez-moi vous montrer cela. Je vous ai dit pourquoi cela pouvait être un avantage. Permettez-moi de vous montrer ce que j'ai fait et comment je l'ai fait.
J'ai appliqué cela à mon SDK Python. Et ce que j'ai fait ici, c'est que j'ai créé une action GitHub. Vous pouvez faire cela dans n'importe quel système de CI. J'utilise les actions GitHub. J'ai créé quelque chose pour les tests de mutation - un morceau très, très simple de YAML. Essentiellement, cette action me permet de choisir manuellement d'exécuter le test de mutation pour ma suite de tests. Et en fait, c'est un choix que j'ai fait de l'exécuter manuellement.
Je ne veux pas qu'il s'exécute automatiquement. Vous pourriez l'exécuter en mode "push", mais j'ai choisi de ne pas le faire. Ainsi, lorsque j'exécute ce programme, vous pouvez voir qu'il ne fait que terminer ce travail. Et ce qu'il fera également, c'est me donner ce rapport HTML. Il me donnera un artefact d'exécution que je pourrai télécharger, ce qui me permettra de voir exactement comment mes tests se déroulent et quels mutants ne sont pas capturés.
Alors, comment faire ? Eh bien, c'est vraiment la question intéressante ici. Je vais vous montrer le YAML que j'ai utilisé. Encore une fois, j'utilise GitHub Actions. C'est ce que j'utilise moi-même, mais vous pouvez le faire avec n'importe quel système de CI - il s'agit juste d'un simple script. Et honnêtement, ce que je dirais aussi, c'est de ne pas hésiter à aller sur le SDK que je maintiens. Le code est là. Vous pouvez prendre le fichier YAML. Et n'hésitez pas à l'utiliser vous-même, vous êtes le bienvenu. Si cela vous permet d'effectuer des tests de mutation, tout le monde y gagnera. Mais quoi qu'il en soit, je vais vous montrer le fichier YAML tout de suite. Je vais vous expliquer ce que fait chaque partie et comment elle fonctionne.
Tout d'abord, vous pouvez voir ici que nous avons un test de mutation YAML. Vous pouvez voir que nous fonctionnons sur Ubuntu. Nous n'utilisons qu'une seule version de Python. Nous pouvons voir ici les différentes étapes. Donc, nous vérifions le code et nous installons Python.
Une fois cela fait, nous installons nos dépendances, mais nous incluons maintenant la dépendance mutmut. Une fois cela fait, nous lançons notre test de mutation, ce que nous faisons avec mutmut runet nous utilisons deux drapeaux. Nous utilisons --no-progressce qui signifie que nos résultats sont meilleurs lorsque nous les lisons dans notre système CI. Nous utilisons également le mode --CI qui nous renvoie un code d'erreur sensé. J'insiste sur ce point parce que c'est ma seule contribution à mutmutmais j'en suis toujours fier, alors je vais le mentionner. C'est en fait très utile ici parce que sinon nous n'obtenons pas un code d'erreur raisonnable et cela fait échouer les actions GitHub. Une fois que nous avons fait cela, nous obtenons cette sortie HTML et nous l'uploadons pour pouvoir la télécharger de GitHub plus tard. Et c'est tout. C'est 35 lignes, c'est tout ce que nous faisons, et c'est tout bon.
Quelles sont les autres préoccupations concernant l'IC ? Quelles sont les autres choses auxquelles vous voulez penser ? Tout d'abord, il faut penser au déclenchement manuel par rapport au déclenchement automatique. Personnellement, j'aime gérer ces choses manuellement parce que je ne veux pas que cela fasse partie d'un processus de relations publiques où il faut obtenir un certain score pour être approuvé.
Je veux l'exécuter lorsque j'ai ajouté quelque chose de nouveau qui pourrait changer les choses ou si j'ai besoin d'un aperçu de mon code. Vous pouvez l'exécuter automatiquement si vous le souhaitez, mais sachez que vous n'êtes pas obligé de le faire. Nous ne voulons pas simplement abstraire la loi de Goodhart à nouveau et essayer de transformer le score de mutation en une nouvelle métrique à abstraire. Il faut aussi penser à la possibilité de fonctionner sur plusieurs systèmes d'exploitation. Pour mon code, je n'en ai pas vraiment eu besoin car je ne m'attends pas à ce qu'il change suffisamment - nous ne jouons pas avec le système d'exploitation. Nous faisons plutôt des appels d'API, ce n'est donc pas très important pour nous. Vous pourriez aussi vouloir utiliser plusieurs versions de vos dépendances et d'autres choses de ce genre, pour voir si des choses changent pour vous aussi.
En résumé, les tests de mutation testent vos tests. Il vous aide à battre la loi de Goodhart pour la couverture du code. Si vous voulez l'utiliser, je vous conseille de commencer petit et localement, mais une fois que vous êtes prêt, utilisez un système de CI afin que vous puissiez faire ce travail de manière asynchrone et que vous ne gaspilliez pas le temps et les ressources de votre machine. Enfin, je voudrais juste dire que les mutants sont précieux, et qu'ils sont aussi merveilleux. Si nous pensons à Henry et à tout ce qu'il nous a donné, il ne peut pas voler, il ne peut pas faire le travail du code dont nous avons besoin, mais ce qu'il a fait nous a donné un tel aperçu de notre base de code qu'il est super merveilleux. Comme je l'ai dit au début de cette présentation, il ne faut pas craindre les mutants, il faut les aimer.
Merci beaucoup. J'ai été très, très heureux de vous parler aujourd'hui. Si vous souhaitez me poser des questions, n'hésitez pas à rejoindre le Slack de la communauté Vonage. Si vous voulez voir le Python SDKn'hésitez pas à y jeter un coup d'œil. Et si vous voulez créer un Account avec Vonage et essayer nos produits, il y a un lien ici aussi.
J'espère que ces éléments vous seront utiles. Merci beaucoup, et à une prochaine fois. A bientôt.
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.