Aucun test n’accompagnait ce module de prise de rendez-vous médicaux, développé sept ans plus tôt par un prestataire aujourd’hui injoignable, et utilisé quotidiennement par plusieurs cabinets de radiologie pour gérer les créneaux de leurs patients. Le code fonctionnait, personne ne savait vraiment pourquoi dans certains cas limites, et une demande d’évolution imposait d’y toucher malgré tout.
Face à ce genre de situation, refactoriser directement sans filet revient à parier que le comportement observé aujourd’hui correspond bien au comportement voulu à l’origine, un pari risqué sur un module qui gère des créneaux médicaux réels. Les tests de caractérisation offrent une alternative plus prudente : documenter ce que le code fait réellement, avant de décider si cela doit changer.
Étape 1 : observer sans juger
La première étape consiste à écrire des tests qui décrivent fidèlement le comportement actuel du code, y compris ses aspects visiblement discutables. Un test de caractérisation ne dit jamais si un comportement est correct : il dit seulement ce qu’il est, aujourd’hui, avant toute modification.
public function test_comportement_actuel_creneau_deja_reserve(): void {
$creneau = $this->create_creneau_reserve();
$resultat = ancienne_fonction_reservation( $creneau->id, $patient_id );
// Comportement observé, pas forcément voulu :
// la fonction retourne true même si le créneau est déjà pris,
// et écrase silencieusement la réservation précédente.
$this->assertTrue( $resultat );
}
Ce test, volontairement inconfortable à lire, documente un bug réel du code existant : deux patients peuvent se voir attribuer le même créneau sans erreur visible. Plutôt que de corriger ce comportement immédiatement dans la même étape, il est d’abord figé par un test, pour être traité consciemment plus tard, en concertation avec le client sur les conséquences métier.
Étape 2 : couvrir les cas limites avant de toucher au code

Une fois le comportement principal caractérisé, la couverture s’étend méthodiquement aux cas limites : créneau à cheval sur un changement d’heure d’été, patient déjà inscrit sur trois créneaux le même jour, annulation à quelques minutes du rendez-vous. Chaque cas limite identifié dans le code, souvent via un commentaire cryptique ou une condition sans explication, devient un test dédié.
- Les créneaux qui chevauchent minuit sont-ils gérés par jour calendaire ou par tranche de 24 heures ?
- Que se passe-t-il si un patient annule puis réserve immédiatement le même créneau ?
- Le fuseau horaire du serveur influence-t-il le calcul des créneaux disponibles ?
Sur ce projet, la couverture des cas limites a révélé sept comportements non documentés, dont trois ont été jugés problématiques par l’équipe métier une fois mis en lumière, et corrigés dans une étape séparée avec l’accord explicite du client.
Utiliser la couverture de code comme guide, pas comme objectif
Un outil de couverture comme pcov aide à repérer les branches de code jamais exercées par les tests de caractérisation en cours d’écriture. Une couverture de 100 % n’est pas l’objectif recherché : certaines branches mortes, du code jamais réellement atteint en production, ne méritent pas d’être caractérisées mais plutôt supprimées directement lors de la refactorisation.
Étape 3 : refactoriser avec le filet en place
Avec cette couverture en place, la refactorisation proprement dite peut commencer, module par module, en exécutant la suite de tests de caractérisation après chaque changement. Tout test qui échoue signale un changement de comportement, qu’il soit voulu ou non, et impose un arrêt pour vérifier lequel des deux cas s’applique.
wp-env run tests-cli phpunit --testsuite=caracterisation --stop-on-failure
Étape 4 : remplacer les tests de caractérisation par de vrais tests
Une fois le comportement clarifié et les corrections validées avec le client, les tests de caractérisation les plus inconfortables (ceux qui documentaient un bug volontairement laissé en l’état) sont réécrits en tests de comportement voulu, avec des noms de méthode et des commentaires qui affirment désormais ce qui est correct, plutôt que ce qui a simplement été observé.
Un test de caractérisation n’est jamais la version finale d’une suite de tests : c’est une étape de transition qui protège le code pendant qu’on apprend enfin à le comprendre.
Notre verdict
Sur un module aussi sensible qu’une prise de rendez-vous médicaux, refactoriser sans ce filet aurait exposé le client à un risque disproportionné par rapport au gain de temps espéré. Les tests de caractérisation, distincts des tests de caractérisation génériques déjà couverts par ailleurs sur des projets non spécialisés, ont ici permis de sécuriser un chantier que personne dans l’équipe n’osait entamer depuis des mois.