Test, Test, Test! Configurare Travis CI per un Progetto Laravel

Usare una soluzione come TravisCI per eseguire i test aumenta la qualità dei nostri progetti. Scopriamo come configurarlo con un progetto Laravel!
francesco
Francesco Malatesta
19/04/2017 in Tutorial

Andando in giro su GitHub, alla scoperta di package e progetti, avremo sicuramente visto dei badge come questi:

Si tratta fondamentalmente di piccoli widget che vanno ad integrarsi con servizi esterni, che offrono le funzioni più disparate. Uno di questi servizi è Travis CI, che offre (gratuitamente per progetti open source) un'infrastruttura già pronta per testare il nostro codice.

Come fa? Semplice: lavorando con un apposito file di configurazione, TravisCI automaticamente:

  • scarica il codice del repository;
  • effettua le operazioni di installazione (dipendenze, configurazioni);
  • lancia il tool dedicato al testing che preferiamo (PHPUnit, nel nostro caso);
  • se è andato tutto bene avremo davanti agli occhi un'accogliente schermata come quella nello screenshot di seguito;
  • in caso di errori verremo notificati via mail;

Una volta registrati TravisCI permette di "aggiungere" il repository di un nostro progetto.

Un'altra cosa più interessante di TravisCI consiste nella possibilità di configurare GitHub in modo tale da impedire il merge di un branch in caso di test non passati. Un ulteriore occhio a conferma della qualità del codice dei nostri progetti, e meno lavoro noioso per noi developer.

Arriviamo quindi a noi: cosa succederà in questo articolo?

  • scopriremo come usare TravisCI per un progetto Laravel, seguendo passo passo la procedura di preparazione di un file di configurazione;
  • faremo esempi per due tipi di test. Unit test ed integration test nello specifico;
  • vedremo infine come GitHub si integra automaticamente con TravisCI, in modo tale da segnalare una PR i cui test non passano oppure mostrarci un bel pulsantone verde nel caso sia andato tutto bene, aggiungendo quindi una buona pratica al nostro flusso di lavoro;

Il codice che scriverò in questo progetto sarà disponibile anche su GitHub, in questo repository.

Pronti? Si comincia!

Primo Impatto con TravisCI

Prima di entrare nel vivo dell'articolo, cerchiamo di capire bene come effettivamente TravisCI funziona.

Come già detto, è possibile aggiungere un proprio repository a Travis effettuando l'accesso da qui con il proprio account GitHub. Aggiungere un repository significa fare in modo che Travis, ad ogni push:

  • si scarichi l'ultima versione della codebase;
  • effettui una serie di operazioni preliminari (installazione delle dipendenze, preparazione dei file e così via);
  • avvii i test usando un qualsiasi tool/framework a nostro piacimento;

Queste cose non avvengono in automatico: dobbiamo dire noi a Travis cosa deve fare, e come.

Dovremo aggiungere, al nostro progetto, un file .travis.yml, che conterrà queste istruzioni in formato Yaml.

Ecco un esempio di .travis.ci specifico per Laravel che ho trovato con una semplice ricerca. Non è detto sia quello che useremo per il nostro progetto: diamoci soltanto uno sguardo per farci un'idea.

language: php

php:
  - 5.6

before_script:
  - cp .env.travis .env
  - mysql -e 'create database homestead_test;'
  - composer self-update
  - composer install --no-interaction

script:
  - vendor/bin/phpunit

Proviamo a capire cosa signfiica:

  • all'inizio diamo a TravisCI un paio di informazioni di base. Il progetto è di tipo PHP, la versione (di PHP) che ci interessa per fare i test è la 5.6;
  • nella sezione before_script stiamo specificando alcuni comandi che dovranno essere eseguiti prima di avviare i test. In questo caso copiamo il file .env, creiamo un database, installiamo le dipendenze;
  • in script avviamo effettivamente i test, usando phpunit;

Niente di troppo complesso comunque: la guida di TravisCI per un progetto PHP spiega abbastanza bene tutte le basi di cui avremo bisogno.

Adesso sporchiamoci un po' le mani!

Iniziamo dalle Basi: Unit Test!

Ok, si parte dal primo livello. In questa sezione creeremo un semplice unit test, lo manderemo su e ci assicureremo che passi, configurando TravisCI per questa prima operazione di base.

Chiaramente, assicuriamoci di aver aggiunto il nostro nuovo progetto su GitHub tra quelli tenuti sotto controllo da TravisCI, altrimenti sarà tutto tempo perso!

Avremo bisogno di un progetto Laravel su cui fare esperimenti: assicuriamoci di aver preparato tutto. Se stiamo usando Linux o MacOS, possiamo usare Vagrant velocemente tramite LaraPrep.

Nella cartella tests/Unit togliamo di mezzo i test già esistenti e creiamone uno nostro. Lo chiameremo CalculationsTests.php.

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class CalculationsTest extends TestCase
{
    /**
     * Un semplice test di base.
     *
     * @return void
     */
    public function testAdd()
    {
        $this->assertEquals(
          4,
          2 + 2
        );
    }

    /**
     * Un altro semplice test di base.
     *
     * @return void
     */
    public function testMultiply()
    {
        $this->assertEquals(
          9,
          3 * 3
        );
    }
}

Possiamo quindi procedere con il creare il file .travis.yml di cui avremo bisogno per spiegare a TravisCI come comportarsi.

Torniamo nella root directory del nostro progetto e creiamo .travis.yml con un primo setup di base.

language: php

php:
  - 5.6

before_script:
  - cp .env.travis .env
  - composer self-update
  - composer install --no-interaction

script:
  - vendor/bin/phpunit

Come la prima linea di before_script suggerisce, una buona pratica è quella di creare un apposito file .env dedicato a Travis, che dovremo copiare prima di eseguire i test. In questo modo sarà più semplice avere delle variabili d'ambiente specifiche per l'ambiente di testing.

Per ora basta copiare il file .env.example che già abbiamo a disposizione di default in un nuovo progetto Laravel.

Ci siamo! Se i file sono tutti possiamo procedere con il push e attendere l'esecuzione dei test su TravisCI.

E infatti...

I test sono stati eseguiti e passano!

Level Up: Integration Test!

Le cose iniziano a farsi divertenti: abbiamo visto come impostare il nostro progetto per poter lavorare con i test unitari... ma come configuriamo TravisCI per gli integration test?

La prima cosa di cui abbiamo bisogno è... un integration test! Creiamone uno al volo usando il model User, già presente in Laravel di default.

Il file sarà tests/Integration/UserTest.php.

<?php

namespace Tests\Integration;

use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class UserTest extends TestCase
{
    use DatabaseMigrations;

    public function testItShouldCreateUser()
    {
        $user = User::create([
          'name' => 'Francesco',
          'email' => 'hey@hellofrancesco.com',
          'password' => 'such-security'
        ]);

        $this->assertDatabaseHas('users', [
          'name' => 'Francesco',
          'email' => 'hey@hellofrancesco.com'
        ]);
    }
}

Definiamo anche una suite integration, visto che non è presente nel file phpunit.xml.

<testsuites>
    <testsuite name="unit">
        <directory suffix="Test.php">./tests/Unit</directory>
    </testsuite>
    <testsuite name="integration">
        <directory suffix="Test.php">./tests/Integration</directory>
    </testsuite>
</testsuites>

Non credo che il codice appena visto abbia bisogno di spiegazioni. Vediamo però, adesso, cosa c'è da aggiungere al file .travis.yml.

language: php

php:
  - 5.6

services:
  - mysql

before_script:
  - mysql -e 'CREATE DATABASE travis_test;'
  - cp .env.travis .env
  - composer self-update
  - composer install --no-interaction
  - php artisan key:generate
  - php artisan migrate

script:
  - vendor/bin/phpunit

Abbiamo aggiunto l'item services, specificando che avremo bisogno di MySQL. TravisCI metterà su automaticamente un database per i nostri test. Dopodichè abbiamo aggiunto alcuni elementi a before_script, chiedendo a MySQL di creare un nuovo database il cui nome è travis_test. Infine, tramite php artisan migrate prepariamo tutto il necessario.

Manca ancora qualcosa però... dobbiamo inserire le credenziali giuste nel file .env.travis per connetterci al database che avremo sulla macchina di test! Aggiungiamole subito...

...
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=travis_test
DB_USERNAME=root
DB_PASSWORD=
...

Di default, sulla macchina di test di Travis usiamo root come user ed il campo password vuoto. Non sono cose inventate ovviamente: basta dare uno sguardo alla documentazione di TravisCI per farsi un'idea di quello di cui possiamo aver bisogno.

Ci siamo: commit, push e mandiamo su il test. Dovrebbe essere tutto ok: adesso Travis riesce a gestire tranquillamente anche i test che richiedono un database.

Integrazione con GitHub

Come già detto in precedenza, è possibile integrare TravisCI con GitHub per bloccare eventuali PR i cui test sono falliti, evitando merge pericolosi.

Di default, questa integrazione è già parzialmente attiva: il servizio infatti verrà richiamato ad ogni nuova push su un qualsiasi branch che fa parte di una PR. Ecco cosa ho visto su una PR di esempio aperta al volo che è possibile vedere qui.

Tuttavia, è possibile aumentare il controllo sui singoli branch e addirittura impedire del tutto il merge nel caso in cui i test siano falliti.

Tutto quello che bisogna fare è andare in "Settings" del nostro repository, cliccare quindi su "Branches" e scegliere il branch che vogliamo "proteggere". Ci ritroveremo davanti una schermata come questa:

Basterà selezionare continuous-integration/travis-ci tra i servizi legati alla regola "require status checks to pass before merging" e cliccare su "Save Changes".

Adesso, infatti, la nostra PR apparirà così...

Conclusioni

In questo semplice articolo mi sono limitato a dare quella che può essere definita "un'infarinatura di base" su TravisCI e la sua configurazione per un progetto Laravel. In verità c'è tanto da vedere: bisognerebbe scriverci un libro, più che un articolo, per poter coprire tutto.

Come punto di partenza, però, dovrebbe essere perfetto per farsi un'idea di come configurare correttamente un progetto per la prima volta. Soprattutto, perfetto per iniziare ad intuire i benefici che può portare al proprio flusso di lavoro.

E voi? Usate TravisCI nei vostri progetti? C'è qualche consiglio in particolare che volete condividere? Fatelo nei commenti qui di seguito, oppure venite a parlarne nel canale Slack di Laravel-Italia.