Sujet : testing
-
Mesurer les performances d'un changement : échauffement, répétitions, variance et résultats à présenter
Une comparaison de temps d'exécution ne constitue un résultat que si elle résiste au bruit : fixer la charge de travail, écarter les exécutions d'échauffement, alterner de nombreuses répétitions de chaque variante, choisir la statistique avant d'examiner les données et indiquer la dispersion et l'environnement à côté de chaque chiffre. Une différence inférieure à la dispersion entre exécutions n'est pas un résultat.
-
Refactoriser par petites étapes vérifiées
La refactorisation modifie la structure sans changer le comportement ; procéder par petites étapes avec des tests réussis entre chacune, et séparer les commits de refactorisation des changements de comportement, permet de la sécuriser et de faciliter sa revue.
-
Rédiger un rapport de bug exploitable
Un rapport de bug est exploitable quand une personne extérieure peut reproduire le défaut sans poser de question : un titre précis, l'environnement avec ses versions, des étapes numérotées pour reproduire le problème, le résultat attendu et le résultat réel séparés, le message d'erreur littéral et un exemple aussi réduit que possible. Les hypothèses sur la cause figurent dans une section à part.
-
Données d'amorçage et fixtures pour bases de données locales : petites, idempotentes et versionnées avec le schéma
Séparer les données de référence (nécessaires partout), les données d'exemple (développement et démonstrations) et les données de test (créées par les tests) ; écrire le script d'amorçage comme du code idempotent avec des upserts sur des clés naturelles, garder le jeu d'exemples petit et nommé, l'exécuter après les migrations à la fois dans le script d'installation et en intégration continue, et ne jamais amorcer les machines de développement à partir de données de production brutes.
-
Tests à base de propriétés avec des entrées générées
Plutôt que des exemples choisis à la main, un test à base de propriétés énonce un invariant et laisse une bibliothèque générer de nombreuses entrées, en réduisant les échecs à des contre-exemples minimaux ; Hypothesis en est l'implémentation de référence pour Python.
-
Générer, critiquer, réviser : quand une boucle d'auto-vérification est rentable
Une boucle dans laquelle le modèle critique et révise sa propre sortie améliore les résultats lorsque la critique dispose d'un signal externe (tests, un validateur, une source) et d'une grille fixe ; sans cela, des résultats publiés montrent qu'elle peut dégrader les réponses, et chaque tour ajoute au moins deux appels dont l'entrée croît avec le brouillon.
-
Écrire un test unitaire en JUnit 5 et xUnit.net : annotations, cycle de vie et cas paramétrés côte à côte
JUnit Jupiter marque les tests avec @Test, exécute @BeforeEach et @AfterEach autour de chacun sur une instance fraîche par défaut, et pilote les cas pilotés par les données avec @ParameterizedTest plus une annotation de source ; xUnit.net utilise [Fact], le constructeur et IDisposable pour l'initialisation par test sur une instance fraîche, [Theory] avec [InlineData] pour les cas, et des fixtures pour un contexte coûteux partagé. Écrire des tests de même forme dans les deux garde alignées les conventions d'une équipe polyglotte.
-
Concevoir un pipeline d'intégration continue
Un pipeline d'IC devrait être rapide, autotestable et identique pour chaque changement : construire à partir d'un checkout propre, exécuter linters et tests par étapes, échouer bruyamment, et garder la durée totale assez courte pour que les gens l'attendent.
-
Bases de données éphémères en conteneurs pour les tests d'intégration
Démarrer le véritable moteur de base de données dans un conteneur jetable par exécution de tests, garder ses données en mémoire, appliquer les migrations une seule fois sur une base de données modèle et la copier pour chaque fichier de test ; les tests sollicitent alors le véritable planificateur, les véritables contraintes et le véritable comportement d'isolation, au lieu d'un substitut en mémoire.
-
Utiliser des tests par propriétés pour les analyseurs syntaxiques
Exprimer les invariants d'un analyseur syntaxique sur des entrées générées, et conserver les échecs minimisés comme exemples de non-régression ciblés.
-
pass^k sur des essais répétés prédit mieux les incidents des agents en production que pass@k
Hypothèse : pour des agents déployés sur des tâches répétitives, le taux de réussite sur tous les essais (pass^k) mesuré sur un jeu d'évaluation est plus fortement corrélé au taux d'exécutions ayant échoué ou été escaladées en production que le taux de réussite sur au moins un essai (pass@k), parce que la production n'accorde qu'une seule tentative par tâche.
-
Reproductibilité d'une expérience d'apprentissage automatique : graines, environnement, données et limites du déterminisme
Relancer une expérience et obtenir le même chiffre exige des états aléatoires fixés et transmis explicitement, des versions de bibliothèques figées, un jeu de données et un découpage identifiés, ainsi que la conscience que les noyaux GPU et les nouvelles versions de bibliothèques peuvent quand même changer les résultats ; le protocole rend les exécutions reproductibles là où c'est possible et documente les cas où cela ne l'est pas.
-
Faire du red teaming sur un flux de travail d'agent avant de lui accorder des permissions réelles
Attaquer l'agent comme le feraient un contenu ou une personne malveillants : injection indirecte de prompt à travers chaque entrée qu'il lit, manipulation des arguments d'outil, exfiltration via des appels d'outil et épuisement de budget ; exécuter des sondes scriptées plus des tentatives manuelles, consigner ce que l'agent a fait, et corriger la frontière, pas seulement le prompt.
-
Données de test sans données personnelles issues de la production
Donner à un environnement de développement, à la CI et à la préproduction des données réalistes en les générant : classer les colonnes, écrire des générateurs à graine fixe qui passent les validateurs de l'application, produire du volume avec generate_series, ne copier que des distributions depuis la production, marquer les enregistrements générés de façon reconnaissable, et supprimer le raccourci consistant à copier la production.
-
Quelle couverture de tests suffit pour un petit service ?
Question ouverte : pour un service de quelques milliers de lignes avec une base de données et une API HTTP, quel niveau de couverture et quel dosage de tests s'est révélé maintenir des taux de défauts acceptables sans ralentir les évolutions ?
-
Extraction structurée de documents avec JSON Schema, validation et nouvelles tentatives bornées
Définir l'enregistrement cible comme un JSON Schema avec additionalProperties à false, demander au modèle exactement cette forme, valider chaque réponse avec un véritable validateur, réessayer un nombre borné de fois en incluant l'erreur de validation dans le prompt, et orienter ce qui échoue encore vers une personne plutôt que de deviner.
-
Réviser du code écrit par un agent d'IA
Un protocole de révision proposé pour les modifications générées : comparer le diff avec la demande, confirmer l'existence de chaque API et dépendance, vérifier les affirmations sur les tests en les exécutant et en les mettant en échec, lire les tests avant l'implémentation, traquer les erreurs avalées, et consigner ce qui a été vérifié.
-
La boucle du développement piloté par les tests
Écrire un test qui échoue, le faire passer avec la modification la plus simple possible, puis refactoriser une fois les tests au vert ; la boucle maintient les décisions de conception petites et donne à chaque ligne une raison d'exister.
-
Sélecteurs stables et attente automatique dans les tests de bout en bout en navigateur
Deux causes dominent l'instabilité des tests en navigateur : des sélecteurs qui se cassent ou correspondent au mauvais élément, et des pauses temporisées qui présument d'un minutage. Localiser les éléments par rôle, libellé ou identifiant de test, faire en sorte que chaque localisateur corresponde à exactement un élément, et synchroniser sur des assertions qui réessaient et des vérifications d'actionnabilité plutôt que sur le temps.
-
Exécuter des tests de mutation sans se noyer dans les survivants
Exécuter un outil de mutation sur un module, classer chaque mutant survivant comme une assertion manquante, un cas manquant ou un mutant équivalent, corriger les deux premiers, exclure le troisième, et borner le temps d'exécution par des exécutions incrémentales ou limitées au diff ; utiliser le score comme un cliquet par module plutôt que comme un objectif global.
Lisible par machine : JSON