# Golden files pour un export CSV ou JSON : détecter un format qui a changé

> Comparer la sortie d'une fonction d'export à un fichier de référence versionné, pour attraper un changement de colonne ou de type non intentionnel avant qu'un client ne le découvre.

- Auteur : Clément Hadrot
- Publié le : 2025-02-15
- Mis à jour le : 2025-02-15
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/golden-files-export-csv-json/

## L’essentiel

- Le fichier de référence sert de contrat implicite avec les intégrations clientes
- La comparaison doit ignorer les valeurs volatiles comme les dates
- Régénérer la référence est un acte volontaire, jamais automatique

**Problème.** Une extension de facturation exporte, chaque nuit, un fichier CSV consommé automatiquement par le logiciel comptable de douze clients différents. Un changement anodin dans le code — renommer une clé de tableau PHP de `montant_ht` à `montant_hors_taxes` pour plus de clarté — a suffi à casser silencieusement l'import comptable chez trois de ces clients, la colonne attendue n'existant plus sous le nom prévu. Aucun test fonctionnel classique n'aurait détecté ce problème puisque l'export continuait de produire un fichier valide, juste avec une colonne renommée.

## Snippet commenté : générer et comparer un golden file

Un golden file (ou fichier de référence) est un exemple de sortie figée, versionné dans le dépôt aux côtés du code, contre lequel chaque exécution future du test compare la sortie réelle produite par la fonction.

> L'essentiel à retenir : Le fichier de référence sert de contrat implicite avec les intégrations clientes ; La comparaison doit ignorer les valeurs volatiles comme les dates ; Régénérer la référence est un acte volontaire, jamais automatique

```
class Test_Export_Facturation extends WP_UnitTestCase {

    private $chemin_reference = __DIR__ . '/fixtures/export-facturation.golden.csv';

    public function test_export_correspond_a_la_reference() {
        // jeu de données fixe, jamais généré aléatoirement, pour un export reproductible
        $factures = [
            [ 'id' => 1001, 'client' => 'Menuiserie Auberval', 'montant_ht' => 450.00, 'tva' => 90.00 ],
            [ 'id' => 1002, 'client' => 'Atelier Cortec', 'montant_ht' => 1280.50, 'tva' => 256.10 ],
        ];

        $csv_genere = generer_export_facturation( $factures );
        $csv_reference = file_get_contents( $this->chemin_reference );

        $this->assertSame(
            $this->normaliser( $csv_reference ),
            $this->normaliser( $csv_genere ),
            'L’export ne correspond plus au format de référence. Si ce changement est volontaire, régénérez le golden file.'
        );
    }

    private function normaliser( $csv ) {
        // supprime les fins de ligne variables entre systèmes d'exploitation
        return str_replace( "\r\n", "\n", trim( $csv ) );
    }
}
```

## Neutraliser les valeurs volatiles avant comparaison

Un export contient souvent un horodatage de génération ou un identifiant de lot qui change à chaque exécution, ce qui casserait la comparaison même en l'absence de toute régression réelle. Il faut soit injecter une horloge fixe dans le test via un filtre dédié, soit neutraliser ces colonnes avant comparaison avec une expression régulière ciblée :

```
private function normaliser( $csv ) {
    $csv = preg_replace(
        '/^Genere le : .*/m',
        'Genere le : [DATE_IGNOREE]',
        $csv
    );
    return str_replace( "\r\n", "\n", trim( $csv ) );
}
```

## Le même principe appliqué à un export JSON

Pour un export JSON, la comparaison brute de chaînes de caractères est fragile face à un simple changement d'ordre des clés, qui ne devrait pas être considéré comme une régression. On compare alors des structures décodées plutôt que du texte :

```
$json_genere = json_decode( generer_export_json( $factures ), true );
$json_reference = json_decode( file_get_contents( $this->chemin_reference_json ), true );

$this->assertEquals( $json_reference, $json_genere );
```

`assertEquals` compare la structure de données sans tenir compte de l'ordre des clés d'un tableau associatif, contrairement à une comparaison textuelle stricte qui échouerait à tort.

## Checklist avant d'accepter un changement de golden file

1. Le changement de sortie est-il documenté dans le ticket ou la pull request, avec la raison précise du changement de format ?
2. Les intégrations clientes connues consommant cet export ont-elles été informées, ou le changement est-il rétrocompatible (ajout de colonne en fin de fichier plutôt que renommage) ?
3. La régénération du golden file se fait-elle dans le même commit que le changement de code, jamais après coup dans un commit séparé qui masquerait la revue ?
4. Une note de version ou un changelog mentionne-t-il le changement de format pour les intégrateurs externes ?

```
# commande de régénération volontaire, jamais lancée automatiquement en CI
php bin/regenerer-golden-files.php --export=facturation
```

## Notre verdict

Un export consommé par des systèmes tiers mérite un contrat de format aussi rigoureux qu'une API versionnée, même s'il s'agit « seulement » d'un fichier CSV généré par une tâche planifiée. Le golden file rend ce contrat explicite et vérifiable automatiquement, ce qui aurait évité l'incident chez nos trois clients concernés : le renommage de colonne aurait fait échouer le test avant même d'atteindre la branche principale, avec un message clair pointant vers la nécessité d'une décision consciente plutôt qu'un renommage accidentel.
