Aller au contenu

Skills

chimera-test-the-wiring-not-the-class

Une classe assemblée à la main dans un test prouve que la classe fonctionne, pas que quoi que ce soit l'atteint — couvrez le chemin que la production emprunte réellement.

PatronProvenance: cleanStatut: activev0.1.0 · Apache-2.0

Conférée par la personne qui a relu la fiche, et non revendiquée par le fichier lui-même. Une fiche que l'agent distille au cours d'une exécution ayant consommé du contenu non fiable naît contaminée et reste en attente de relecture avant d'être un jour récupérée.

Quand elle vient à l'esprit

  • ça marche en test, pas dans l'app
  • composant ajouté derrière une factory ou un registre
  • le flag est désactivé par défaut
  • suite verte, comportement cassé

C'est dans À éviter et Vérifier que se trouve d'ordinaire la valeur. À faire est la section que tout le monde écrit.

Le corps de la fiche ci-dessus est une traduction. L'original anglais est ce que la CLI importe, ce que l'agent lit à l'exécution et ce que l'empreinte ci-dessous atteste.

Déclencheur

Vous avez construit un composant que la production atteint indirectement : via une fabrique, un registre, un chargeur de plugins, un flag de configuration, un routeur, un point d'entrée de CLI, un conteneur d'injection de dépendances. Vos tests le construisent directement et appellent ses méthodes.

Chacun de ces tests peut passer alors que le composant est inatteignable dans le système en fonctionnement — parce que rien en eux n'exerce l'enregistrement, la valeur par défaut du flag, ou la branche de l'assembleur qui décide de l'inclure ou non.

Cela ne s'applique pas à une fonction pure que les appelants importent et appellent directement. Là, l'import est le câblage, et un test unitaire le couvre. Cela ne s'applique pas non plus quand vous testez délibérément un algorithme isolément — ces tests-là sont justes et doivent rester ; cette carte dit seulement qu'ils ne suffisent pas à eux seuls.

À faire

  1. Nommez le point d'entrée qu'un utilisateur atteint réellement : la sous-commande de CLI, la route HTTP, la boucle d'exécution de l'agent, la tâche planifiée. Écrivez-le avant d'écrire le test.

  2. Écrivez au moins un test qui démarre et ne passe aucun argument de constructeur pour votre composant. Si le test doit nommer votre classe pour que la fonctionnalité se produise, il ne teste pas le câblage.

  3. Construisez l'objet comme la production le construit — appelez la vraie fabrique ou le vrai chargeur de configuration :

    # WRONG — proves the class, not the wiring: the component is handed to the thing under test,
    # so the test passes whether or not anything in production ever hands it over.
    assert "reminder" in render(feature=Feature(text="reminder"))
    
    # RIGHT — build it the way the entry point builds it, then look for the same observable
    assert "reminder" in build_the_real_way(config).render()
    

    Le cas de Chimera vaut d'être cité parce que la classe n'a jamais été cassée. Les skill cards avaient un récupérateur qui marchait, un stockage qui marchait et un injecteur qui marchait — et chimera/config.py:244 contient skill_cards: bool = Field(default=False, ...), si bien que sur un déploiement standard rien n'a jamais été injecté. Tous les tests unitaires passaient. La mesure qui a fini par le détecter comptait les skills créées face aux skills injectées et a trouvé 39 contre zéro.

  4. Vérifiez un observable qui ne peut apparaître que si le composant a été atteint : du texte dans le prompt rendu, une ligne écrite, une entrée de journal, un code de sortie.

  5. Vérifiez la valeur par défaut. Si la fonctionnalité est livrée derrière un flag, ajoutez un test distinct qui lit la valeur par défaut sans aucune surcharge et vérifie ce qu'elle vaut. Une suite qui ne tourne jamais qu'avec le flag forcé à l'activation ne peut pas vous dire ce que reçoivent les utilisateurs.

À éviter

Assembler à la main les collaborateurs que la production câble. La forme de l'échec est une classe de handler entièrement couverte par des tests unitaires que le routeur n'enregistre jamais, ou une capacité dont la clé de configuration vaut « désactivé » par défaut — la classe est correcte, les tests sont corrects, et la fonctionnalité ne fait rien dans le produit. Rien n'est rouge, donc rien n'est investigué, et le trou survit jusqu'à ce qu'un humain essaie la fonctionnalité à la main.

Évitez aussi de simuler la jointure que vous cherchez justement à couvrir. Patcher la fabrique, ou stubber le chargeur de configuration pour qu'il renvoie un objet contenant votre composant, supprime exactement le code que le test existait pour exercer :


monkeypatch.setattr(mod, "load_plugins", lambda: [MyPlugin()])

Simulez plutôt à la frontière la plus externe — le client réseau, l'horloge, l'appel au LLM — et laissez réel tout ce qui se trouve entre le point d'entrée et votre composant.

Vérifier

Supprimez le câblage et lancez la suite. Commentez la ligne d'enregistrement : le décorateur @register, l'entrée du dictionnaire de dispatch, l'appel include_router(...), la valeur par défaut dans le schéma de configuration.

Puis la question binaire : un test est-il passé au rouge, et était-ce un test qui ne mentionne jamais votre classe par son nom ?

Si la suite reste verte, votre couverture est purement au niveau de la classe et le câblage n'est pas testé. Si le seul test rouge est celui qui construit la classe directement, même réponse. Restaurez ensuite la ligne et confirmez le vert — et faites git diff avant de committer, pour que l'enregistrement supprimé ne parte pas en production.

Risque

Les tests de point d'entrée sont plus lents, plus difficiles à déboguer, et localisent moins bien : quand l'un échoue, vous savez que la fonctionnalité est cassée mais pas lequel des dix composants l'a cassée. C'est un coût réel, et la mauvaise réponse à cette carte est de supprimer vos tests unitaires au profit de tests de bout en bout. Gardez les deux — le test de câblage vous dit *qu'*il y a une casse, le test unitaire vous dit quoi.

Passer par le vrai point d'entrée peut aussi toucher des choses que vous ne voulez pas toucher en CI : une API payante, une base de données de production, un système de fichiers hors du bac à sable. Si le seul moyen d'atteindre le point d'entrée est de dépenser de l'argent ou de muter la production, ne le forcez pas ; couvrez plutôt directement la fonction d'assemblage et acceptez d'être à un pas du vrai chemin.

Et cette carte porte sur l'atteignabilité, pas sur la justesse. Une fonctionnalité peut être parfaitement câblée au point d'entrée et produire quand même la mauvaise réponse ; un test de câblage au vert n'autorise donc pas à se dispenser de vérifier ce que la sortie dit réellement.

L'utiliser

La fiche est une donnée. Clonez le dépôt et importez-la par son chemin — ce qui arrive par le réseau est traité comme contaminé et retenu pour approbation, ce qui est le comportement souhaitable et la raison pour laquelle il n'y a pas d'installateur en une ligne ici.

git clone https://github.com/brcampidelli/chimera-agent.git
chimera skills-import chimera-agent/skills/chimera-test-the-wiring-not-the-class/SKILL.md

Intégrité

SHA-256 du fichier tel qu'il est publié. Qui l'importe peut vérifier que ce qu'il a reçu correspond à ce que cette page affichait.

564f2b0aaff3bbb51ca9bfa013d89e3d47d92166f498803c688c3b859b378475

Lire la fiche dans le dépôt