---
title: "Égalité sensible"
type: "test-smell"
slug: "sensitive-equality"
url: "http://localhost:3000/fr/test-smells/sensitive-equality.md"
category: "Odeurs d'assertion"
description: "Un test vérifie le comportement en comparant la représentation textuelle d'un objet (toString(), JSON.stringify(), HTML rendu) à un littéral de chaîne attendu, couplant ainsi le test à un formatage accessoire plutôt qu'aux valeurs qui comptent réellement."
---
# Égalité sensible

> Un test vérifie le comportement en comparant la représentation textuelle d'un objet (toString(), JSON.stringify(), HTML rendu) à un littéral de chaîne attendu, couplant ainsi le test à un formatage accessoire plutôt qu'aux valeurs qui comptent réellement.

## Signs and Symptoms

Vous reconnaissez une Égalité sensible lorsque le côté _réel_ d'une assertion sérialise un objet en texte et que son côté _attendu_ est un littéral de chaîne qui regroupe de nombreux champs avec des séparateurs, des guillemets, des crochets et des espaces.

Signes révélateurs :

* La valeur réelle provient de `.toString()`, `String(x)`, d'un littéral de gabarit (template literal), de `JSON.stringify(...)`, `wrapper.html()`, `el.outerHTML`, ou d'une capture instantanée d'un bloc sérialisé.
* La valeur attendue est une longue chaîne littérale (souvent collée à partir d'une exécution en échec précédente) et vous ne pouvez pas dire d'un coup d'œil _quelle_ partie correspond à l'élément testé.
* Le test se casse lors de changements qui n'affectent pas le comportement : clés réordonnées, espaces ajoutés/supprimés, précision numérique, format de date, locale, fuseau horaire, ou ordre d'itération des `Map`/`Set`/objets.

```js
// Comparaison d'une forme sérialisée à un littéral de chaîne
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');

// Assertion sur la sortie de toString()
expect(order.toString()).toBe('Order[id=7, total=42.00, items=2]');

// Comparaison du HTML rendu complet à un littéral
expect(wrapper.html()).toBe('<div class="card"><h2>Bob</h2><span>30</span></div>');

// Comparaison de chaînes sensible à la locale/au fuseau horaire
expect(d.toString()).toBe('Mon Jun 15 2026 00:00:00 GMT+0000 (UTC)');

```

## Reasons for the Problem

**Pourquoi cela arrive**

* C'est rapide et facile. Comme le notent van Deursen et al. dans _Refactoring Test Code_, il est rapide de calculer un résultat réel, de le convertir en chaîne et de le comparer à un littéral de chaîne représentant la valeur attendue — souvent, le littéral est simplement copié à partir d'une exécution en échec. Les outils de capture instantanée (snapshot) rendent cela encore plus tentant.
* L'objet n'a pas d'égalité significative (`equals`/comparateur profond) câblée, ou le graphe d'objets est volumineux, de sorte que le sérialiser en chaîne _semble_ plus simple que de faire une assertion champ par champ.

**Pourquoi cela nuit**

* **Fragilité / faux échecs.** La chaîne transporte de nombreux détails sans rapport — virgules, guillemets, espaces, ordre des clés, précision des flottants, locale, fuseau horaire, ordre d'itération des collections. Chaque fois que le format de `toString()`/sérialisation change, des tests sans rapport commencent à échouer alors même que le comportement est correct. C'est une cause classique de [Test fragile](http://xunitpatterns.com/Fragile%20Test.html).
* **Maintenabilité.** Un seul changement de formatage ou de bibliothèque oblige à modifier de nombreux tests, et le gigantesque littéral attendu est fastidieux à mettre à jour et facile à se tromper subtilement.
* **Lisibilité / intention masquée.** Un mur de texte comme valeur attendue masque ce qui est réellement vérifié ; un relecteur ne peut pas voir le seul champ qui intéresse le test.
* **Fausse confiance.** Un bloc sérialisé en chaîne peut passer pour de mauvaises raisons (deux états distincts qui se sérialisent vers le même texte), et il incite les développeurs à réenregistrer le littéral/la capture en cas d'échec sans vérifier que la nouvelle valeur est réellement correcte.
* **Instabilité (flakiness).** Les chaînes sensibles à la locale, au fuseau horaire et à l'ordre font dépendre les résultats de l'environnement dans lequel le test s'exécute.

## Treatment

Faites vos assertions sur les **données**, et non sur leur rendu.

1. **Comparez les valeurs structurées avec une égalité profonde** plutôt qu'avec une égalité de chaîne (`toEqual`/`toStrictEqual`), qui est indépendante de l'ordre et des espaces pour les objets.
2. **Ne vérifiez que les attributs pertinents** avec des comparateurs partiels (`toMatchObject`, `expect.objectContaining`) afin qu'un changement de formatage ailleurs ne puisse pas casser le test.
3. **Analysez, ne comparez pas des chaînes.** Lorsque vous recevez une charge utile sérialisée (par exemple, un corps JSON d'API), reconvertissez-la en structure et comparez les structures.
4. **Introduisez une méthode d'égalité/de comparaison** sur l'objet (la refactorisation recommandée par van Deursen et al.) et faites une assertion d'égalité d'objets plutôt qu'une égalité de `toString()`.
5. **Si vous devez comparer une sortie sérialisée, canonicalisez-la d'abord** — triez les clés, fixez la locale/le fuseau horaire, fixez la précision numérique — et préférez une capture instantanée relue à un littéral en ligne collé à la main.
6. **Pour les tests de DOM/composants, interrogez de manière sémantique** (Testing Library `getByRole`, `toHaveTextContent`) au lieu de comparer le HTML complet.

```js
// Avant — Égalité sensible
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');

// Après — égalité structurelle (indépendante de l'ordre des clés / des espaces)
expect(user).toEqual({ name: 'Bob', age: 30 });

// Après — assertion uniquement sur le champ testé
expect(user).toMatchObject({ age: 30 });

```

```js
// Avant — comparaison de chaîne sur une charge utile d'API
expect(res.text).toBe('{"id":7,"total":42}');

// Après — comparaison des structures analysées
expect(JSON.parse(res.text)).toEqual({ id: 7, total: 42 });

```
