Začínáme s PHPUnitem – základní test

Dejte mi půl hodiny a já vás naučím napsat test! Tento text slouží jako základní návod pro účastníky veřejného školení, nicméně by měl pomoci všem vývojářům v PHP, kteří testy ještě pořád nepíší a myslí si, že to je složité nebo zdlouhavé. Mám na vás jediné přání: pište se mnou. Kdo dnes napíše svůj první test, ozvěte se v komentářích článku a vyptejte se, co jste nepochopili, co vám šlo/nešlo.

Instalace

Nejdřív si nainstalujte PEAR. Každý, kdo to s PHP myslí vážně, PEAR má (ostatně zkuste si představit programátora v Rails bez Gemu nebo Linuxáka bez balíčkovacího systému). Přesto pokud PEAR nemáte, instalujte podle návodu na výše odkázané stránce.

Samotná instalace PHPUnitu je primitivní. Do příkazové řádky zadejte:

pear channel-discover pear.phpunit.de
pear channel-discover pear.symfony-project.com
pear install phpunit/PHPUnit

Pokud nepoužíváte Windows, instalace proběhne v pořádku. Pokud je máte, je šance tak padesát na padesát, že budete muset použít alternativní návod. Že se instalace podařila, poznáte tak, že do příkazové řádky napíšete phpunit a dostanete výstup podobný tomuto:

PHPUnit 3.4.12 by Sebastian Bergmann.
Usage: phpunit [switches] UnitTest [UnitTest.php]
       phpunit [switches] <directory>
... (dlouhý výpis všemožných voleb)

Šablona testu

A teď si zopakujeme šablonu z předchozího dílu a trochu si ji postupně rozepíšeme.

Test je třída. Obvykle jednu třídu kódu testujeme jednou až několika třídami testů. Mám-li třídu Article, test pojmenovávám ArticleTest (pokud je jich víc, můžeme třídu pojmenovat třeba ArticleSaveTest, ArticleListTest etc.). Důležité je, aby název souboru končil na Test, jinak PHPUnit nepozná, že je v souboru právě třída testu. Existují sice způsoby, jak to obejít, ale na ně pro příštích několik let v klidu zapomeňte.

Třída testu dědí z PHPUnit_Framework_TestCase. Aby byla tato třída přístupná, musíme před třídu napsat require_once "PHPUnit/Framework.php". Mnohem lepší je ale napsat to jednou do souboru bootstrap.php, který si uložíte do složky s testy a budete ho requirovat ve všech testech. Časem zjistíte, že těch společných úkonů na začátku testů je s rostoucím rozsahem systému stále víc.

Samotné testování funkcionality se provádí ve veřejných metodách, které začínají na slovíčko test. Tedy například testSaveData, testValidate… můžete se orientovat podle názvů metod dané třídy, ale není to žádné pravidlo.

Před každým testem se spouští metoda setUp. V té si většinou vytváříme instanci testovaného kódu, dáváme prostředí do výchozího stavu, který je společný všem testům.

class ArticleTest extends PHPUnit_Framework_TestCase
{
    protected function setUp()
    {
    }
    public function testSave()
    {
        // kod testu
    }
}

Pamatujte si, že test nemá „otestovat každou řádku“, ale podstatu té třídy. Tedy to, co dělá, jak změní prostředí a co vrátí. Test musí jít za podstatou, když otestujete tu, o moc víc zatím testovacího kódu psát nemusíte. To přijde časem samo!

Při vývoji testu si většinou vystačíte s velmi snadnou šablonou:

  1. test se nazývá stejně jako třída s připojeným slovem Test na konci
  2. testujte všechny metody mimo setterů a jděte po tom, co se vrátí a co se změní, když nastavíte dané podmínky
  3. v setupu si vytvářejte objekt, který budete testovat
  4. vkládejte nějaký bootstrap a ne přímo PHPUnit/Framework.php, často se Vám bude hodit mít nějaký kód společný (i u poměrně malých aplikací to bývá config).

Asserty

Pro otestování stavu vráceného výsledku (ale i například změny souboru na disku) se používají takzvané asserty. PHPUnit nabízí širokou škálu, my si popíšeme ty nejčastěji používané. Přesto byste si měli pamatovat, že existují i asserty pro testování existence/obsahu souboru a pro testování struktury a obsahu XML.

Nejčastější asserty jsou:

assertTrue($predanaHodnotaKteraMaBytTrue)
assertFalse($predanaHodnotaKteraMaBytFalse)
assertType("ocekavany typ", $predanaHodnota)
assertEquals("ocekavana hodnota", $predanaHodnota)

Použití v testu je následující (předpokládám ještě použití dibi):

class ArticleTest
{
    protected function setUp()
    {
        dibi::query("truncate table articles");
        $this->object = new Article;
    }
    public function testSave()
    {
        // vykonam kod
        $data = array("name"=>"Muj clanek", "content"=>"Lorem");
        // otestuju navratovou hodnotu
        $this->assertTrue($this->object->save($data));
        // otestuju zmenu, ktera mela nastat
        $this->assertEquals("Lorem", dibi::query("select content from articles where name = 'Muj clanek'")->fetchSingle());
    }
}

Spouštění testů

Test lze spustit více způsoby (populární je především podpora v různých IDE), my si teď povíme o základním způsobu v příkazové řádce.

Předpokládejme, že testy máte v rootu projektu ve složce tests (nemusím připomínat, že root projektu není totéž, co document_root). Vejděte do složky projektu. Pokud je phpunit správně nainstalovaný, když napíšete phpunit tests, spustí se testy (soubory končící na Test obsahující třídu končící na Test). Pokud zadáte přímo phpunit tests/ArticleTest.php, spustí se jeden konkrétní test case.

Praktická cvičení

Máme třídu Calculator:

class Calculator
{
    const ZERO_DIVIDER_CODE = 0;
    public function divide($a, $b)
    {
        if (0 == $b)
            throw new InvalidArgumentException("Cannot divide by zero", self::ZERO_DIVIDER_CODE);
        return $a / $b;
    }
}

Cvičení 1:

Napište test, který ověří funkčnost třídy.

Cvičení 2:

Napište si test pro funkci multiply a factorial a pak implementujte kód, který projde testem.

Cvičení 3:

Vytvořte si třídu, která bude serializovat na disk objekty (do souborů) a pak z nich bude zase objekty vytahovat. Vždy napište nejdřív test, pak napište kód.

V případě problémů se ozvěte do komentářů.

Tato série slouží jako základní materiál pro školení testování, které pořádá Internet Info spolu s autorem článku Jiřím Kneslem. Mimo školení testování nabízí Jiří Knesl i školení Zend Frameworku, agilních technik a metodik.

Jiří Knesl se zabývá hlavně Scrumem a správným vývojem software (prevence chyb, vyšší produktivita).

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 26

Přehled komentářů

Honza Marek PHPUnit a dibi
Vrtak-CZ Reklama - Instalace
Lukas Rychtecky Hezky clanek
Satai Re: Hezky clanek
Aleš Roubíček Re: Hezky clanek
Satai Re: Hezky clanek
Aleš Roubíček Re: Hezky clanek
Satai Re: Hezky clanek
Borek Bernard Integrační test
vetesnik Díky
Aleš Roubíček Špatně, špatně, špatně
Borek Bernard Re: Špatně, špatně, špatně
Jiří Knesl Re: Špatně, špatně, špatně
Aleš Roubíček Re: Špatně, špatně, špatně
Jiří Knesl Re: Špatně, špatně, špatně
Oldis Re: Špatně, špatně, špatně
Aleš Roubíček Re: Špatně, špatně, špatně
Oldis Re: Špatně, špatně, špatně
Aleš Roubíček Re: Špatně, špatně, špatně
Borek Bernard Re: Špatně, špatně, špatně
Aleš Roubíček Re: Špatně, špatně, špatně
Jiří Knesl Re: Špatně, špatně, špatně
Aleš Roubíček Re: Špatně, špatně, špatně
Borek Bernard Re: Špatně, špatně, špatně
Michal Sänger PHPUnit na Windows s XAMPP
Daniel Suchý Zprovoznění PHPUnit
Zdroj: https://www.zdrojak.cz/?p=3258