Průběžné testování s Travis CI

Znáte to. Napsali jste testy, které teď procházejí, poplácali se po zádech a váš spánek začal být mnohem klidnější. Máte jistotu, že váš kód spolehlivě funguje. A pak se to stane. Hodiny ukazují 3:15 a do nočního ticha se zakousne nepříjemný zvuk drnčení mobilu na nočním stolku. Volá šéf. Zase to nefunguje. Zalije vás studený pot. Vždyť na to máme testy! V tu chvíli se vynoří vzpomínka na páteční odpoledne – spěcháte domů a zapomínáte spustit testy po poslední úpravě.

Abyste předešli podobným zážitkům, ukážeme si, jak průběžně testovat pomocí populárního nástroje Travis CI:

Jak funguje Travis CI

Travis CI (dále jen Travis) je velmi populární služba pro automatizaci průběžné integrace. Je poskytována zdarma a nabízí automatizované spouštění testů po zápisu změny do repozitáře. Je plně integrována do prostředí GitHubu.

Travis se konfiguruje souborem .travis.yml umístěným v kořenovém adresáři projektu. Obsahuje několik bloků, které si podrobněji popíšeme. Ani jeden z bloků není povinný. Pokud bychom ovšem vynechali script, Travis by se snažil spouštět testy pomocí phpunit.

Bloky jsou spouštěny v pořadí:

  • before_install
  • install
  • before_script
  • script
  • after_success nebo after_failure
  • after_script

Soubor .travis.yml dovoluje odsazovat pouze mezerami. Syntaktickou správnost si můžete ověřit pomocí validátoru.

Pro podrobnější informace si přečtěte oficiální dokumentaci.

Vytvoření .travis.yml

Nastavení jazyka

Nejprve je potřeba pomocí language Travis informovat, pro jaký jazyk má prostředí nastavit. Na dalších řádcích uvádíme, pro jaké verze PHP budeme chtít náš projekt otestovat. Neuvedení setinkového čísla znamená použití nejnovější dostupné verze. Testy pak budou spuštěny pro každou verzi zvlášť.

language: php

php:
  - 7.1
  - 7.2
  - 7.3
  - 7.4
  - nightly  # vývojová verze

Proměnné prostředí

V sekci env nastavujeme další varianty prostředí pro běh testů. Pro každou odrážku se skripty provedou samostatně a v jedné odrážce lze definovat více proměnných. Dále v textu budeme používat proměnnou TESTER_PHP_BIN, abychom mohli testy pouštět také s parametrem -p php-cgi.

env:
  - TESTER_PHP_BIN="php"
  - TESTER_PHP_BIN="php-cgi"

Uvedené sekce php a env nám zajistí spuštění testů celkem 10×. Pro pět verzí PHP a dvě varianty proměnných prostředí.

Instalace závislostí

Návod předpokládá, že závislosti testovaného projektu jsou spravovány pomocí nástroje Composer, a nette/tester je uveden jako závislost pro vývoj. Jak nastavit Composer najdete v kapitole Composer.

V bloku install nainstalujeme pomocí Composeru závislosti našeho projektu. Každá odrážka znamená samostatný příkaz. Composer ve výchozím nastavení nainstaluje i dev závislosti. Dobrým zvykem je použít --no-interaction, protože Travis si s Composerem neumí povídat. Použijeme i --prefer-source kvůli omezenému počtu požadavků na GitHub API.

Composer je již v Travisu nainstalován, ale my chceme použít nejnovější verzi, proto v bloku before_install provedeme jeho update.

before_install:
  - composer self-update

install:
  - composer install --no-interaction --prefer-source

Matice testů

Na základě předchozích údajů je vytvořena testovací matice, tedy varianty prostředí, ve kterých budou testy spuštěny (v našem příkladě 10 variant). Nastavení matice je umožněno v bloku matrix.

Chceme-li některou z variant vyřadit, využijeme blok exclude. Nebudeme chtít spouštět testy starších verzí PHP s binárkou php-cgi.

matrix:
  exclude:
    - php: 7.0
      env: TESTER_PHP_BIN="php-cgi"

    - php: 7.1
      env: TESTER_PHP_BIN="php-cgi"

Aby testování bylo označeno Travisem jako úspěšné, musí testy projít ve všech prostředích. Pokud nechceme, aby výsledek některé z nich ovlivňovalo, můžeme to deklarovat v bloku allow_failures. V našem případě nám nebude vadit, pokud neprojdou testy na vývojové verzi PHP.

matrix:
  allow_failures:
    - php: nightly

Všimněte si, že jsme uvedli pouze verzi PHP. Travis se zachová tak, že do celkového výsledku nezahrne všechny kombinace s verzí nightly. Pokud nyní testy na nightly selžou, ale v jiných prostředích projdou, bude i celý build označen jako procházející.

Spouštění testů

Testy se spouštějí v sekci script, kde stačí zavolat tester. Předpokládejme, že testy jsou umístěny ve složce tests/ a používáte vlastní php.ini umístěné ve složce s testy. Pomocí -s si necháme vypsat informace o přeskočených testech. Jako binárku nastavíme v parametru -p hodnotu proměnné TESTER_PHP_BIN, kterou jsme si nastavili v bloku env.

script:
  - ./vendor/bin/tester -p $TESTER_PHP_BIN -s -c ./tests/php.ini ./tests

Když se něco pokazí

Blok after_failure se provede, pokud testy selžou. Tester při chybné aserci ukládá aktuální obsah proměnných do souborů *.actual. V tomto bloku si je můžeme vypsat.

after_failure:
  # Vytiskne obsah souborů *.actual
  - for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done

Nastavení dalších služeb

Travis nám umožňuje zapnout další služby. Například Redis server na který ukládáte cache.

services:
  - redis-server

Inicializace databáze:

Databáze MySQL je již předinstalována. Běží na adrese 127.0.0.1 a přihlásit se můžete na účet travis nebo root bez hesla. Pokud byste chtěli spouštět integrační testy, můžete si do ni naimportovat testovací databázi, kterou máte například v souboru tests/testbase.sql:

before_script:
  - mysql -u root -e 'CREATE DATABASE testbase;'
  - mysql -u root testbase < tests/testbase.sql

Výsledný soubor

Celý .travis.yml pak vypadá takto:

language: php

php:
  - 7.1
  - 7.2
  - 7.3
  - 7.4
  - nightly

env:
  - TESTER_PHP_BIN="php"
  - TESTER_PHP_BIN="php-cgi"

matrix:
  allow_failures:
    - php: nightly

  exclude:
    - php: 7.0
      env: TESTER_PHP_BIN="php-cgi"

    - php: 7.1
      env: TESTER_PHP_BIN="php-cgi"

services:
  - redis-server

before_install:
  - composer self-update

install:
  - composer install --no-interaction --prefer-source

before_script:
  - mysql -u root -e 'CREATE DATABASE testbase;'
  - mysql -u root testbase < tests/testbase.sql

script:
  - ./vendor/bin/tester -p $TESTER_PHP_BIN -c ./tests/php.ini -s ./tests/

after_failure:
  # Vytiskne obsah souborů *.actual
  - for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done

Integrace s GitHubem

Jak již bylo zmíněno dříve, Travis je integrován do prostředí GitHubu. Aby mohly být testy spouštěny ve správný okamžik, je potřeba nastavit tzv. Webhook, který informuje Travis o změně ve vašem repozitáři.

Nastavení Webhooku

Nejprve je potřeba se přihlásit pomocí vašeho GitHub účtu. To provedete na hlavní stránce pomocí odkazu Sign in. Po synchronizaci uvidíte repozitáře, ke kterým máte přístup, a u nich jednoduchý přepínač. Přepnutím do polohy ON zapnete hook.

Travis nyní po každém pushnutém commitu nebo po vytvoření pull-requestu zařadí váš repozitář do testovací fronty a po chvilce čekání budou spuštěny testy.

Status obrázek

Můžete si dokonce nechat vygenerovat obrázek, který informuje o stavu vašeho repozitáře. Ten pak můžete vložit například do svého readme.md.

Vynechání testů u commitu

Některé commity není nutné testovat. Uveďte kdekoliv v commit message parametr [ci skip] a Travis bude tento commit ignorovat.