Gains :
- Capacité à empêcher l'intelligence artificielle d'accepter un comportement erroné comme « correct » en calculant la valeur attendue dans les tests unitaires indépendamment de la règle d'acceptation
- Capacité à imprimer des tests rapides, indépendants et reproductibles en appliquant les principes AAA et FIRST et en se moquant des dépendances externes
- Capacité à tester des tests avec mutation (décryptage de code) et à reconnaître le code difficile à tester comme une odeur de conception
La couche la plus grande et la plus rapide de la pyramide des tests est celle des tests unitaires : des tests qui vérifient une fonction ou un petit morceau de code indépendamment de tout le reste. Des milliers de tests unitaires s'exécutent en quelques secondes et détectent un bug alors que le code est encore sur l'écran du développeur. L’intelligence artificielle (IA) est peut-être la plus compétente pour produire des tests unitaires : vous lui confiez une fonction, l’IA produit des dizaines de tests. Mais cette commodité même donne lieu au plus grand piège : l'IA produit facilement des tests qui « s'allument en vert mais ne vérifient rien » ou acceptent le comportement actuel (peut-être défectueux) du code comme « correct ». Dans cette unité, vous apprendrez comment écrire des tests unitaires véritablement protecteurs avec l'IA et la relation entre le code testable et l'IA.
Qualités d'un bon test unitaire : PREMIER
Les bons tests unitaires suivent les PREMIERS principes : rapides, indépendants (les tests ne doivent pas dépendre les uns des autres), répétables (répétables - même résultat dans n'importe quel environnement), auto-validants (réussite/échec clair), opportuns (à temps). Rappelez-vous ces principes lorsque vous demandez à l’IA de produire des tests ; demander spécifiquement que le test ne dépende pas du monde extérieur (base de données réelle, réseau, horloge) pour être "indépendant" et "répétable".
Modèle AAA et affirmation expressive
Un test unitaire solide suit la structure AAA : Arrange (préparer - configurer les entrées et les dépendances), Act (exécuter - appeler la fonction testée), Assert (valider - comparer le résultat avec la valeur attendue). Le point critique est l’affirmation. L’erreur la plus courante commise par l’IA est de dériver l’assertion de la sortie du code testé – la logique « tout ce que le code renvoie est vrai ». Cela rend le test vide de sens. La bonne méthode consiste à déterminer indépendamment la valeur attendue (à partir des critères d'acceptation, la calculer manuellement).
Attention : si vous dites à l'IA "écrire un test pour cette fonction", l'IA peut exécuter la fonction et écrire sa sortie comme "attendue". Ce test réussit même si la fonction est fausse. Dites plutôt "vous calculez les résultats attendus selon ces règles, ne faites pas référence à la sortie actuelle de la fonction".
Mocks, stubs et dépendances
Les tests unitaires nécessitent un isolement. Si votre fonction dépend d'une base de données ou d'une API, elles sont remplacées par des objets fictifs (mock/stub — un substitut factice et contrôlé à la dépendance réelle) lors des tests. Cela rend le test rapide, indépendant et reproductible. L'IA peut produire une installation simulée ; Mais méfiez-vous des moqueries excessives : si vous vous moquez de tout, le test ne vérifiera que "ce que renvoie la simulation", et non la logique réelle. Équilibre : imiter le monde extérieur, exécuter la vraie logique testée.
Testabilité et IA
Il y a un retour intéressant : le code difficile à tester est souvent du code mal conçu. Si l'IA a du mal à écrire des tests sur une fonction (trop de dépendances, état global caché, effets secondaires), c'est une odeur de conception. Demander à l’IA « comment refactoriser ce code pour le rendre testable » conduit à la fois à de meilleurs tests et à un meilleur code.
Tests paramétrés et diversité des données
Écrire un test distinct à chaque fois pour vérifier la même règle avec des entrées différentes est à la fois fastidieux et difficile à maintenir. Les tests paramétrés – une structure qui exécute de manière répétée la même logique de test sur une liste d’entrées et de résultats attendus – éliminent cette répétition : un seul corps de test est alimenté par des dizaines de paires d’entrées. L’IA est très efficace pour produire ces tableaux de résultats attendus lorsque vous lui donnez vos règles d’acceptation ; Il répertorie notamment systématiquement les valeurs limites et les classes d’équivalence.
Mais il y a ici aussi un piège : l'IA a tendance à dériver les résultats attendus dans le tableau généré à partir du code testé. Cette erreur est encore plus dangereuse dans les tests paramétrés, car une seule logique incorrecte invalide des dizaines de lignes. Par conséquent, faites toujours calculer la colonne des résultats attendus indépendamment selon la règle d’acceptation et validez manuellement au moins quelques lignes. Demandez également une colonne de description « que représente chaque ligne » ; Ainsi, lorsqu'une ligne est interrompue, vous voyez instantanément quel état est interrompu.
Astuce : Ajoutez intentionnellement une « ligne de piège » à la table de test paramétrée, c'est-à-dire que vous faites sciemment une erreur de saisie du résultat. Si cette ligne ne devient pas rouge lorsque vous exécutez le test, votre test ne vérifie pas réellement cette situation. Il s’agit d’une vérification rapide et simulée.
Invite faible/Invite forte
Faible : "Écrivez un test unitaire pour cette fonction."
Fort : Écrivez des tests unitaires [langage/framework] pour la fonction "taxCalculate(amount, rate). Règle d'acceptation : résultat = montant * taux, arrondi à 2 décimales ; un montant ou un taux négatif génère une erreur ; renvoie 0 si le taux est 0. Utilisez la structure AAA. Calculez manuellement les valeurs attendues selon CES règles ; ne faites pas référence à la sortie actuelle de la fonction. Couvrez les cas liés et négatifs (0, négatif, très grand, arrondi aux décimales). Laissez le nom de chaque test décrire la règle. il vérifie la dépendance externe "Non".
Invite puissante ; Il donne la règle d'acceptation, l'espérance de valeur attendue indépendante, la structure et les cas extrêmes. Ainsi, le test devient le gardien de la règle et non le miroir du code.
Tableau de qualité des tests unitaires
symptôme
Mauvais test (fausse confiance)
bon essai
affirmer
Aucun ou "non nul"
Valeur concrète attendue
Source de valeur attendue
Sortie de la fonction
Règle d'acceptation / calcul manuel
dépendance
Base de données/réseau/heure réelle
Isolé avec maquette/tronçon
cas limite
Seule route heureuse
limite, négatif, erreur
Quand tu casses le code
reste vert
devient rouge
Nom
test1, méthode de test
décrit la règle qu'il confirme
Quatre modèles copiables
1) Tests unitaires basés sur des règles :
Votre rôle : ingénieur senior de tests logiciels.Rédiger un test unitaire sur la fonction suivante avec [langage/framework] : [signature].Règles d'acceptation : [règles].- Utiliser la structure AAA.- Calculer manuellement les valeurs attendues selon CES règles ; NE faites PAS référence à la sortie actuelle de la fonction. - Couvrez le chemin limite, négatif, erreur et heureux avec des tests séparés. - Laissez chaque nom de test décrire la règle qu'il vérifie. - Dépendances externes simulées ; Faites fonctionner la logique réelle.
2) Contrôle de la résistance aux mutations :
Découvrez ces tests unitaires. Énumérez 5 modifications mineures que je pourrais apporter au code testé (un - au lieu d'un +, un >= au lieu d'un >, un décalage de limite) et dites-moi pour chacun LEQUEL de ces tests deviendra rouge ? Si aucun n'est renvoyé, le test est insuffisant.Code + tests : [coller]
3) Examen de testabilité :
Pourquoi est-il difficile d’écrire un test unitaire pour cette fonction ? Addiction cachée, statut mondial, effets secondaires, les responsabilités sont-elles nombreuses ? Suggérer une refactorisation minimale pour le rendre testable ; ne changez pas de comportement. Code : [coller]
4) Réalisation incomplète du scénario :
La fonction suivante et les tests disponibles sont donnés. Répertoriez les comportements/cas extrêmes qui n'ont JAMAIS été testés (écart de portée) et ajoutez un test pour chacun. Fonction+tests : [coller]
trois mini-cases
Cas 1 — Testez la mise en miroir du code. Un développeur a demandé à l'IA d'écrire un test pour la fonction d'arrondi ; 10 tests étaient verts. En fait, la fonction arrondissait dans le mauvais sens, mais l'IA avait pris les valeurs attendues de la sortie de la fonction, donc les tests ont considéré l'erreur comme « vraie ». Lorsque les valeurs attendues ont été calculées manuellement avec le modèle « piloté par des règles », 4 tests sont devenus rouges et la véritable erreur a été révélée.
Cas 2 — La valeur du contrôle des mutations. Une équipe s'est appuyée sur 45 tests unitaires. J'ai essayé 20 modifications mineures du code avec un « contrôle de robustesse des mutations » ; les tests n’en ont détecté que 11. Les 9 perturbations restantes se sont déroulées silencieusement. L'équipe a renforcé les tests faibles ; Une erreur de calcul réelle a été détectée par ces tests améliorés dans la prochaine version.
Cas 3 — L'impossibilité de test est une odeur de conception. L'IA ne pouvait pas écrire de tests pour une fonction de commande, elle avait constamment besoin de la véritable base de données. Le modèle « examen de testabilité » a montré que la fonction intégrait l'accès à la base de données. Lorsque l’injection de dépendances a été supprimée, des tests ont pu être écrits et le code est devenu plus propre.
Erreurs courantes
- Dériver la valeur attendue du code. L'IA accepte la sortie de la fonction comme « correcte » ; test qui confirme le code défectueux.
- Testez sans assertion ou avec assertion triviale. "Il n'a pas commis d'erreur, il a réussi" la logique ; Cela ne confirme rien.
- Moquerie extrême. Se moquer de tout et tester uniquement ce que renvoie la simulation ; la vraie logique n'est pas testée.
- Juste la route heureuse. Contournement des états limites, négatifs et d'erreur.
- Ne pas tester en cassant le code. Faire confiance au vert sans vérifier les mutations.
- Ignorer l'intestabilité. Ne pas reconnaître et corriger une mauvaise conception au lieu de pousser des tests approfondis.
En résumé
Les tests unitaires constituent la couche la plus rapide et la plus grande de la pyramide des tests ; Il détecte l'erreur au moment le moins cher. L'IA est tout à fait capable de produire des tests unitaires, mais son plus grand piège est d'écrire des tests qui supposent qu'un comportement incorrect est « correct » en dérivant la valeur attendue du code lui-même. Solution : donner les règles d'acceptation, faire calculer manuellement les valeurs attendues, appliquer les principes AAA et FIRST, se moquer du monde extérieur et exécuter la logique réelle, et tester chaque test par mutation (casser le code). Un code difficile à tester est un signe de conception qui doit être corrigé.
Tâche de candidature
Sélectionnez une fonction qui contient une règle métier de votre propre projet. Écrire des règles d'acceptation et demander à l'IA d'écrire des tests avec le modèle « tests unitaires basés sur des règles » ; Faites calculer manuellement les valeurs attendues. Appliquez ensuite le « contrôle de robustesse des mutations » : faites au moins 5 petites pauses dans le code et mesurez combien de tests deviennent rouges. Ajoutez un nouveau test pour les corruptions non détectées. Indiquez le nombre de perturbations détectées (comme le score de mutation).
liste de contrôle
- [ ] J'ai donné les règles d'acceptation et j'ai fait calculer manuellement les valeurs attendues.
- [ ] Je me suis assuré que les tests ne dérivaient pas la valeur attendue du code.
- [ ] J'ai établi des tests indépendants conformément aux directives AAA et FIRST.
- [ ] Je me suis moqué des dépendances externes et j'ai exécuté la logique réelle.
- [ ] J'ai couvert les cas limites, négatifs et d'erreur.
- [ ] En cassant le code (mutation), j'ai prouvé que les tests protègent effectivement.