# Tester les routines de mise à jour d’une extension entre deux versions

> Simuler une installation ancienne, déclencher la routine de migration et vérifier l'état final des données dans PHPUnit, sans passer par une vraie mise à jour manuelle.

- Auteur : Clément Hadrot
- Publié le : 2021-06-25
- Mis à jour le : 2021-06-25
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/tester-routines-mise-a-jour-extension/

## L’essentiel

- Simuler l'ancienne version via une option de version forcée
- Vérifier l'état des données après migration, pas seulement l'absence d'erreur
- Tester aussi une mise à jour depuis plusieurs versions en retard

Une extension de réservation stockait initialement les créneaux horaires sous forme de chaîne de texte libre, avant qu'une version 2.0 ne les fasse migrer vers un format structuré en tableau sérialisé. La routine de migration fonctionnait très bien sur les installations qui étaient passées par toutes les versions intermédiaires, mais un client resté bloqué sur la version 1.2 depuis deux ans a vu sa migration échouer silencieusement en sautant directement à la 2.0, laissant des créneaux à moitié convertis. Le cas n'avait jamais été testé, parce que personne n'avait pensé à simuler un saut de plusieurs versions d'un coup.

Tester une routine de migration ne consiste pas à vérifier qu'elle s'exécute sans erreur, mais à vérifier que les données sont dans l'état attendu après son passage, en partant d'un état initial représentatif d'une vraie ancienne installation.

## Simuler une ancienne version installée

La plupart des extensions stockent leur numéro de version de schéma dans une option dédiée, distincte du numéro de version du plugin lui-même. Il suffit de forcer cette option avant de déclencher la routine :

```
class Test_Migration_Creneaux extends WP_UnitTestCase {

    public function setUp(): void {
        parent::setUp();
        update_option( 'mon_plugin_db_version', '1.2' );
    }

    public function test_migre_les_creneaux_texte_vers_tableau_structure() {
        $post_id = self::factory()->post->create( array( 'post_type' => 'reservation' ) );
        update_post_meta( $post_id, '_creneau', '14h-16h' );

        mon_plugin_executer_migrations();

        $creneau_migre = get_post_meta( $post_id, '_creneau_structure', true );
        $this->assertSame( array( 'debut' => '14:00', 'fin' => '16:00' ), $creneau_migre );
    }
}
```

## Vérifier l'état final, pas seulement l'absence d'erreur

Un test qui se contente d'appeler la fonction de migration sans assertion sur les données ne prouve rien de solide. Les vérifications utiles portent sur plusieurs aspects :

- La donnée migrée a la forme attendue dans le nouveau format
- L'ancienne métadonnée a bien été supprimée ou conservée, selon ce qui est documenté
- L'option de version de schéma a été mise à jour vers la nouvelle valeur
- La migration ne s'exécute qu'une seule fois, même si le hook se déclenche plusieurs fois

> L'essentiel à retenir : Simuler l'ancienne version via une option de version forcée ; Vérifier l'état des données après migration, pas seulement l'absence d'erreur ; Tester aussi une mise à jour depuis plusieurs versions en retard

## Tester un saut de plusieurs versions

Le cas qui casse le plus souvent en production est celui d'une installation restée bloquée loin en arrière, qui doit exécuter plusieurs migrations intermédiaires d'un coup lors d'une seule mise à jour :

```
public function test_migre_depuis_une_tres_ancienne_version() {
    update_option( 'mon_plugin_db_version', '1.0' );
    // ... créer des données représentatives du format 1.0

    mon_plugin_executer_migrations();

    $this->assertSame( '2.0', get_option( 'mon_plugin_db_version' ) );
    // ... vérifier que les données sont dans le format final 2.0,
    // pas seulement dans un format intermédiaire 1.5
}
```

Ce test aurait directement révélé le bug décrit en introduction : la routine de migration enchaînait bien les étapes 1.0 → 1.5 et 1.5 → 2.0 en théorie, mais une des deux étapes intermédiaires supposait à tort que l'étape précédente avait toujours été exécutée par une version antérieure du plugin, ce qui n'était pas le cas pour ce client précis.

## Tester l'idempotence de la migration

Une routine de migration mal protégée peut se redéclencher plusieurs fois, par exemple si le hook `plugins_loaded` vérifie la version à chaque chargement de page. Il faut donc vérifier qu'exécuter la migration deux fois de suite ne corrompt pas les données déjà migrées :

```
mon_plugin_executer_migrations();
$premiere_valeur = get_post_meta( $post_id, '_creneau_structure', true );

mon_plugin_executer_migrations();
$deuxieme_valeur = get_post_meta( $post_id, '_creneau_structure', true );

$this->assertSame( $premiere_valeur, $deuxieme_valeur );
```

## En résumé

Une routine de migration bien testée couvre trois angles : la migration standard depuis la version précédente immédiate, le saut depuis une version très ancienne, et la ré-exécution accidentelle. La conception de la stratégie de migration elle-même — un numéro de version unique ou des migrations versionnées indépendantes — est un choix d'architecture distinct, qui se prend en amont de ces tests.
