Test automatizzati con PHPUnit

Ottavo articolo della serie sui fondamenti dello sviluppo di plugin WordPress. Negli articoli precedenti abbiamo aggiunto PHPCS per lo stile e PHPStan per la correttezza. Ora completiamo la pipeline di qualità con test automatizzati che verificano il comportamento del plugin.

PHPCS controlla come appare il codice. PHPStan controlla se è logicamente corretto. PHPUnit controlla se fa quello che deve fare. I test automatizzati ti danno la sicurezza di modificare e far crescere il plugin senza rompere ciò che già funziona.

Alla fine di questo articolo avrai PHPUnit configurato, il tuo primo test scritto e il tutto integrato nella pipeline CI. Ricordi la cartella tests/ dall’articolo su Git? È il momento di usarla.

Cos’è PHPUnit e perché testare

PHPUnit è il framework di test standard per PHP. Permette di scrivere due tipi principali di test: i test unitari, che verificano singole funzioni o metodi in isolamento, e i test di integrazione, che verificano il comportamento all’interno di un ambiente WordPress completo.

Perché investire tempo nei test? Tre motivi concreti: sicurezza nel refactoring, perché sai subito se qualcosa si rompe; cattura delle regressioni, perché un bug corretto una volta non torna; e documentazione vivente, perché i test descrivono il comportamento atteso.

Non serve una copertura del 100% dal primo giorno. Anche un singolo test è meglio di nessun test.

Installazione via Composer

Installa PHPUnit e i polyfill necessari come dipendenze di sviluppo:

composer require --dev phpunit/phpunit \
    yoast/phpunit-polyfills

Il pacchetto phpunit/phpunit è il framework stesso. Il pacchetto yoast/phpunit-polyfills è richiesto dalle utilità di test di WordPress core per garantire compatibilità tra diverse versioni di PHPUnit — ti servirà quando scriverai test di integrazione.

Configurazione con phpunit.xml.dist

Come per PHPCS e PHPStan, PHPUnit usa un file di configurazione con la convenzione .dist. Crea phpunit.xml.dist nella root del plugin:

<?xml version="1.0"?>
<phpunit
    bootstrap="tests/bootstrap.php"
    colors="true"
    verbose="true"
    beStrictAboutTestsThatDoNotTestAnything="true"
>
    <testsuites>
        <testsuite name="unit">
            <directory>tests/Unit/</directory>
        </testsuite>
    </testsuites>
</phpunit>

Poi crea il file di bootstrap e la struttura delle directory:

mkdir -p tests/Unit

Crea tests/bootstrap.php:

<?php

declare(strict_types=1);

require_once dirname(__DIR__) . '/vendor/autoload.php';

Per i test unitari, caricare l’autoloader di Composer è sufficiente. Non serve WordPress, non serve un database — stiamo testando pura logica PHP.

Il primo test

Scriviamo un test concreto. Prima, crea una semplice classe di utilità in src/StringHelper.php:

<?php

declare(strict_types=1);

namespace YourVendor\MyAwesomePlugin;

class StringHelper
{
    public static function slugify(string $input): string
    {
        $slug = strtolower(trim($input));
        $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
        $slug = preg_replace('/[\s-]+/', '-', $slug);

        return $slug;
    }
}

Ora crea il test in tests/Unit/StringHelperTest.php:

<?php

declare(strict_types=1);

namespace YourVendor\MyAwesomePlugin\Tests\Unit;

use PHPUnit\Framework\TestCase;
use YourVendor\MyAwesomePlugin\StringHelper;

class StringHelperTest extends TestCase
{
    public function testSlugifyConvertsSpacesToDashes(): void
    {
        self::assertSame(
            'hello-world',
            StringHelper::slugify('Hello World')
        );
    }

    public function testSlugifyRemovesSpecialCharacters(): void
    {
        self::assertSame(
            'hello-world',
            StringHelper::slugify('Hello, World!')
        );
    }
}

Per far funzionare l’autoloading dei test, aggiungi la sezione autoload-dev al tuo composer.json:

{
    "autoload-dev": {
        "psr-4": {
            "YourVendor\\MyAwesomePlugin\\Tests\\": "tests/"
        }
    }
}

Esegui composer dump-autoload e poi lancia i test:

vendor/bin/phpunit

Vedrai un output verde: OK (2 tests, 2 assertions). Quel messaggio è una delle piccole soddisfazioni dello sviluppo software — e la conferma che il tuo setup funziona.

Test con wp-env

I test unitari verificano logica PHP pura. Ma cosa succede quando vuoi testare hook, filtri o interazioni con il database di WordPress? Per questo servono test di integrazione, e qui entra in gioco l’istanza di test di wp-env dall’articolo sull’ambiente locale.

Per eseguire PHPUnit all’interno del container wp-env:

wp-env run tests-cli --env-cwd=wp-content/plugins/my-awesome-plugin \
    vendor/bin/phpunit

Questo comando esegue PHPUnit nell’istanza di test (porta 8889), dove hai accesso a un WordPress completo con database. Per i test di integrazione avrai bisogno di un bootstrap dedicato che carica le utilità di test di WordPress core — un argomento che merita un approfondimento a parte, ma la struttura è già pronta: basta aggiungere una directory tests/Integration/ e una seconda test suite in phpunit.xml.dist.

Integrazione in GitHub Actions

Aggiungi il Composer script, seguendo il pattern ormai familiare:

{
    "scripts": {
        "test": "phpunit"
    }
}

Nell’articolo su GitHub Actions avevamo preparato lo step. Per i test unitari, attivarlo è immediato:

      - name: Run tests
        run: composer run test

Per i test di integrazione in CI, serve avviare wp-env nel workflow:

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Start wp-env
        run: |
          npm install -g @wordpress/env
          wp-env start

      - name: Run integration tests
        run: wp-env run tests-cli --env-cwd=wp-content/plugins/my-awesome-plugin vendor/bin/phpunit

Con questo, ogni Pull Request passa attraverso la pipeline completa: PHPCS per lo stile, PHPStan per la correttezza e PHPUnit per il comportamento. Tre livelli di verifica automatica.

Prossimi passi

La pipeline di qualità è completa. Hai un setup professionale che copre l’intero ciclo: un repository Git ben strutturato, Composer per dipendenze e autoloading, wp-env come ambiente di sviluppo, GitHub Actions per l’automazione, PHPCS per gli standard, PHPStan per l’analisi statica e PHPUnit per i test.

Questo è il fondamento su cui costruire qualsiasi plugin WordPress. Nei prossimi articoli della serie esploreremo lo sviluppo di blocchi Gutenberg e le particolarità dello sviluppo per installazioni Multisite — argomenti che si appoggiano direttamente su questa base.

Ricorda: non serve essere perfetti dal primo giorno. Inizia con un test, aggiungi un livello PHPStan, correggi uno sniff PHPCS alla volta. La qualità si costruisce gradualmente.

Autore: realloc