# assertEqualsWithDelta remplace un delta calculé à la main sur des flottants

> Un test sur un prix ou un pourcentage échoue de temps en temps, sans raison apparente. La précision des nombres flottants est presque toujours en cause.

- Auteur : WordPress Développement
- Publié le : 2020-11-23
- Mis à jour le : 2020-11-23
- Catégorie : Tests
- URL : https://www.wpmoderne.fr/tests/assertequalswithdelta-comparer-flottants-phpunit/

## L’essentiel

- Une tolérance explicite plutôt qu'un calcul de delta manuel
- Utile pour les prix, taux et pourcentages
- Évite les échecs intermittents liés à l'arithmétique flottante

`0.1 + 0.2 === 0.3` retourne `false` en PHP, comme dans la quasi-totalité des langages qui utilisent la représentation binaire des nombres à virgule flottante définie par la norme IEEE 754. Ce n'est pas un bug : c'est une conséquence directe de la façon dont un ordinateur stocke un nombre décimal en binaire, et cela concerne directement les tests qui manipulent des prix, des taux de TVA ou des pourcentages calculés.

Un test qui compare deux flottants avec `assertSame` ou `assertEquals` classique échoue parfois pour une différence de l'ordre de 0,0000000000001, invisible à l'affichage mais bien réelle en mémoire. PHPUnit propose une assertion dédiée à ce problème précis.

## Le symptôme typique

```
public function test_calcule_le_montant_ttc(): void {
    $montant_ht = 19.99;
    $taux_tva   = 0.2;

    $montant_ttc = $montant_ht * ( 1 + $taux_tva );

    // Échec intermittent : 23.988 attendu, 23.987999999999996 obtenu
    $this->assertEquals( 23.988, $montant_ttc );
}
```

Ce test peut passer sur une machine et échouer sur une autre, selon la version de PHP ou l'architecture du processeur, ce qui en fait un classique des suites qui semblent instables sans raison identifiable. Le problème n'est ni dans le code métier, ni dans le test lui-même, mais dans la comparaison exacte de deux valeurs qui ne devraient être vérifiées qu'à une précision donnée.

## La solution : une tolérance explicite

> L'essentiel à retenir : Une tolérance explicite plutôt qu'un calcul de delta manuel ; Utile pour les prix, taux et pourcentages ; Évite les échecs intermittents liés à l'arithmétique flottante

```
public function test_calcule_le_montant_ttc(): void {
    $montant_ht = 19.99;
    $taux_tva   = 0.2;

    $montant_ttc = $montant_ht * ( 1 + $taux_tva );

    $this->assertEqualsWithDelta( 23.988, $montant_ttc, 0.001 );
}
```

Le troisième argument, ici `0.001`, définit l'écart maximal toléré entre les deux valeurs pour que le test soit considéré comme réussi. Toute différence inférieure à ce seuil est ignorée, ce qui reflète fidèlement l'intention réelle du test : vérifier qu'un calcul produit le bon résultat, pas qu'il produit exactement la même suite de bits qu'un calcul de référence.

## Choisir la bonne tolérance

Le choix du delta dépend directement du contexte métier :

- Pour un montant en euros affiché avec deux décimales, une tolérance de `0.001` ou `0.005` est généralement suffisante.
- Pour un pourcentage affiché sans décimale, une tolérance plus large comme `0.5` peut être acceptable selon la précision réellement attendue.
- Pour un calcul scientifique où chaque décimale compte, une tolérance beaucoup plus fine, par exemple `0.0000001`, garde le test rigoureux tout en absorbant l'imprécision propre aux flottants.

Une tolérance trop large masque de vraies erreurs de calcul ; une tolérance trop fine réintroduit le problème initial. Le bon réglage se détermine en réfléchissant à la précision réellement significative pour l'utilisateur final, pas à la précision brute que PHP peut techniquement représenter.

## Pourquoi pas un calcul de delta manuel

Avant l'existence de cette assertion dédiée, la pratique consistait à calculer la différence absolue soi-même :

```
$this->assertLessThan( 0.001, abs( 23.988 - $montant_ttc ) );
```

Ce code fonctionne, mais il a deux défauts. D'abord, il inverse la lisibilité de l'intention : on lit une comparaison de différence plutôt qu'une comparaison de valeurs. Ensuite, en cas d'échec, le message d'erreur produit par `assertLessThan` n'indique que la différence calculée, sans jamais montrer les deux valeurs d'origine, ce qui complique le diagnostic. `assertEqualsWithDelta` affiche les deux valeurs comparées, la tolérance utilisée, et un message d'échec directement exploitable.

> Sur un test qui manipule des prix, la question à se poser n'est jamais « ces deux flottants sont-ils identiques bit à bit », mais « ces deux montants sont-ils identiques à l'euro ou au centime près ». La tolérance doit répondre à cette seconde question, pas à la première.

## Le cas particulier des tableaux de flottants

Cette assertion fonctionne aussi sur des tableaux, ce qui est utile pour comparer une série de montants calculés en une seule fois, par exemple les lignes d'une facture. Le delta s'applique alors à chaque paire de valeurs correspondantes, ce qui évite d'écrire une boucle manuelle avec une assertion répétée pour chaque ligne.

## En résumé

Comparer des flottants avec une égalité stricte revient à ignorer une réalité technique inhérente à leur représentation binaire. `assertEqualsWithDelta` rend cette tolérance explicite, lisible dans le code du test, et affiche un message d'échec directement utile en cas de problème. C'est le choix par défaut à privilégier dès qu'un calcul en PHP produit un résultat décimal, plutôt que d'attendre le premier échec intermittent pour s'en souvenir.
