IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

3. diel - Testovanie v PHP - Dokončenie unit testov

V minulej lekcii, Úvod do unit testov v PHP a inštalácia PHPUnit , sme si nainštalovali framework Codeception a vygenerovali svoj prvý PHPUnit test. Dnes pokryjeme testy našu jednoduchú triedu, uvedieme si dostupné asserční metódy a naše unit testy v PHP dokončíme.

Pokrytie triedy testy

Metódy _before() (starší názov bol setUp()) a _after() (starší názov bol tearDown()) sa zavolajú pred, resp. po každom teste v tejto triede. To je pre nás veľmi dôležité, pretože podľa best practices chceme, aby boli testy nezávislé. Obvykle teda pred každým testom pripravujeme znovu to isté prostredie, aby sa vzájomne vôbec neovplyvňovali. O dobrých praktikách sa zmienime detailnejšie neskôr. Do triedy si pridajme atribút $kalkulacka a v metóde _before() v ňom vždy vytvorme čerstvo novú kalkulačku pre každý test. Pokiaľ by ju bolo ešte potrebné ďalej nastavovať alebo bolo treba vytvoriť ďalšie závislosti, boli by tiež v tejto metóde. Metódu testSomeFeature() odstránime:

class KalkulackaTest extends \Codeception\Test\Unit
{
    /**
     * @var \UnitTester
     */
    protected $tester;

    private $kalkulacka;

    protected function _before()
    {
    $this->kalkulacka = new Kalkulacka();
    }

    protected function _after()
    {
    }
}

Máme všetko pripravené na pridávanie samotných testov. Jednotlivé metódy budú vždy začínať na "test" a budú testovať jednu konkrétnu metódu z triedy Kalkulacka, typicky pre niekoľko rôznych vstupov. Ak vás napadá prečo metódy označujeme prefixy, umožňuje nám to vytvoriť si aj pomocné metódy, ktoré môžeme v danom teste využívať a ktoré nebudú považované za testy. PhpStorm nám totiž testy (metódy začínajúce na "test") automaticky spustí a vypíše ich výsledky.

Pridajme nasledujúcich 5 metód:

public function testScitani()
{
    $this->assertEquals(2, $this->kalkulacka->secti(1, 1));
    $this->assertEquals(1.42, $this->kalkulacka->secti(3.14, -1.72), '', 0.001);
    $this->assertEquals(2/3, $this->kalkulacka->secti(1/3, 1/3), '', 0.001);
}

public function testOdcitani()
{
    $this->assertEquals(0, $this->kalkulacka->odecti(1, 1));
    $this->assertEquals(4.86, $this->kalkulacka->odecti(3.14, -1.72), '', 0.001);
    $this->assertEquals(2/3, $this->kalkulacka->odecti(1/3, -1/3), '', 0.001);
}

public function testNasobeni()
{
    $this->assertEquals(2, $this->kalkulacka->vynasob(1, 2));
    $this->assertEquals(-5.4008, $this->kalkulacka->vynasob(3.14, -1.72), '', 0.001);
    $this->assertEquals(0.111, $this->kalkulacka->vynasob(1/3, 1/3), '', 0.001);
}

public function testDeleni()
{
    $this->assertEquals(2, $this->kalkulacka->vydel(4, 2));
    $this->assertEquals(-1.826, $this->kalkulacka->vydel(3.14, -1.72), '', 0.001);
    $this->assertEquals(1, $this->kalkulacka->vydel(1/3, 1/3));
}

/**
 * @expectedException InvalidArgumentException
 */
public function testDeleniVyjimka()
{
    $this->kalkulacka->vydel(2, 0);
}

K porovnávanie výstupu metódy s očakávanou hodnotou používame poděděné metódy Assert *. Dajú sa volať aj staticky, ale my zostaneme u inštančného použitie. Najčastejšie asi použijete assertEquals(), ktorá prijíma ako prvý parameter očakávanú hodnotu a ako druhý parameter hodnotu aktuálny. Toto poradie je dobré dodržiavať, inak budete mať hodnoty vo výsledkoch testov opačne. Ako asi viete, desatinné čísla sú v pamäti počítača reprezentovaná binárne (ako inak :) ) A to spôsobí určitú stratu ich presnosti a tiež určité ťažkosti pri ich porovnávaní. Preto musíme v tomto prípade zadať aj štvrtý parameter a to je delta, teda kladná tolerancia, o koľko sa môže očakávaná a aktuálna hodnota líšiť, aby test stále prešiel. Tretím parametrom je chybová hláška, ak test neprebehne. Väčšinou ju nie je dôvod zadávať, ak je test dobre pomenovaný az hodnôt jednoducho spoznáme, ktorý Assert sa nepodaril.

Všimnite si, že skúšame rôzne vstupy. Sčítanie netestujeme len ako 1 + 1 = 2, ale skúsime celočíselné, desatinné aj negatívne vstupy, oddelene, a overíme výsledky. V niektorých prípadoch by nás mohla zaujímať tiež maximálna hodnota dátových typov a podobne.

Posledný test overuje, či metóda vydel() naozaj vyvolá výnimku pri nulovom deliteľmi. Ako vidíte, nemusíme sa zaťažovať s try-catch bloky, stačí nad metódu pridať PHP anotáciu @expectedException a uviesť tu triedu výnimky, ktorá sa očakáva. Ak výnimka nenastane, test zlyhá. Pre testovanie viac prípadov vyvolanie výnimky týmto spôsobom by bolo treba pridať viac metód.

Dostupné Assert metódy

Okrem metódy assertEquals() môžeme použiť ešte mnoho ďalších, určite sa snažte použiť tú najviac vyhovujúce metódu, sprehľadňuje to hlášky pri zlyhaní testov a samozrejme aj následnú opravu. Zoznam Assert metód je pomerne vyčerpávajúce a môžete si ho jednoducho prezrieť v IDE, spomeňme si teda len tie najdôležitejšie:

  • assertContains ($ ihla, $ kôpka) - Skontroluje, či $ kôpka (pole) obsahuje danú hodnotu ($ ihla).
  • assertCount ($ ocekavanyPocet, $ kolekcia) - Skontroluje, či má $ kolekcie $ ocekavanyPocet prvkov.
  • assertFalse ($ hodnota) - Skontroluje, či je hodnota false.
  • assertTrue ($ hodnota) - Skontroluje, či je hodnota true.
  • assertNotEquals ($ ocekavanaHodnota, $ hodnota) - Skontroluje, či hodnoty nie sú rovnaké. Podobná "Not" metóda je pre väčšinu Assert, ďalšie tu už nebudeme zbytočne zmieňovať.
  • assertGreaterThan ($ ocekavanaHodnota, $ hodnota) - Skontroluje, či je $ hodnota väčšia ako $ ocekavanaHodnota.
  • assertGreater­ThanOrEqual ($ ocekavanaHodnota, $ hodnota) - Skontroluje, či je $ hodnota väčšia alebo rovná $ ocekavanaHodnota.
  • assertLessThan ($ ocekavanaHodnota, $ hodnota) - Skontroluje, či je $ hodnota menšia ako $ ocekavanaHodnota.
  • assertLessTha­nOrEqual ($ ocekavanaHodnota, $ hodnota) - Skontroluje, či je $ hodnota menšia alebo rovná $ ocekavanaHodnota.
  • assertNull ($ hodnota) - Skontroluje, či je hodnota null.
  • assertSame ($ ocekavanaHodnota, $ hodnota) - Funguje rovnako ako assertEquals(), ale kontroluje aj zhodu dátových typov.

Sú tu aj pripravené Assert pre testovanie atribútov, reťazcov (napr. Či niečím začína), polí, priečinkov, súborov a XML.

AssertThat ()

Veľmi zaujímavá je ešte metóda assertThat(), ktorá umožňuje alternatívny prístup k assercím. Napr. v Jave (PHPUnit pomerne jasne vychádza z JUnit) tento spôsob prináša navyše ďalšie možnosti kontroly dátových typov, v PHP si ho spomeňme skôr len pre zaujímavosť a ukážme si, ako by vyzeral prvý Assert z našich testov pomocou assertThat(). Pripomeňme si pôvodný variant:

$this->assertEquals(2, $this->kalkulacka->secti(1, 1));

A verzie s assertThat():

$this->assertThat(
    $this->kalkulacka->secti(1, 1),
    $this->equalTo(
        2
    )
);

Výhodou je, že zápis vyzerá ako anglická veta. Nevýhodou je vyšší objem kódu a rekurzívne ponáranie. Pre zložitejšie Assert môže byť tento spôsob výhodný.

Spustenie testov

Testy spustíme príkazom:

test run unit

Uvidíme výsledky, ktoré vyzerajú nejako takto:

> C:\xampp\php\php.exe codecept.phar run unit
Codeception PHP Testing Framework v2.3.8
Powered by PHPUnit 6.5.6 by Sebastian Bergmann and contributors.

Unit Tests (5) -------------------
+ KalkulackaTest: Scitani (0.01s)
+ KalkulackaTest: Odcitani (0.00s)
+ KalkulackaTest: Nasobeni (0.00s)
+ KalkulackaTest: Deleni (0.00s)
+ KalkulackaTest: Deleni vyjimka (0.00s)
----------------------------------


Time: 314 ms, Memory: 8.00MB

OK (5 tests, 13 assertions)

Process finished with exit code 0 at 19:32:44.
Execution time: 467 ms.

Ak vám Codeception hlási problém s nedostupnosťou príkazu "php", otvorte konfiguračný súbor codeception.yml a do sekcie settings pridajte hodnotu lint: false.

...
settings:
    bootstrap: _bootstrap.php
    colors: false
    memory_limit: 1024M
    lint: false
...

V určitých verziách sa inak môže zle vyhodnotiť výstupný stav.

Skúsme si teraz urobiť v kalkulačke chybu, napr. Zakomentujte vyvolávanie výnimky pri delení nulou a vráťme vždy hodnotu 1:

public function vydel($a, $b)
{
    //if ($b == 0)
    //  throw new \InvalidArgumentException("Nelze dělit nulou!");
    return 1;
}

A spustite znovu naše testy:

> C:\xampp\php\php.exe codecept.phar run unit
Codeception PHP Testing Framework v2.3.8
Powered by PHPUnit 6.5.6-2 by Sebastian Bergmann and contributors.

Unit Tests (5) -------------------
+ KalkulackaTest: Scitani (0.01s)
+ KalkulackaTest: Odcitani (0.00s)
+ KalkulackaTest: Nasobeni (0.00s)
x KalkulackaTest: Deleni (0.00s)
x KalkulackaTest: Deleni vyjimka (0.00s)
----------------------------------


Time: 334 ms, Memory: 8.00MB

There were 2 failures:

---------
1) KalkulackaTest: Deleni
 Test  tests\unit\KalkulackaTest.php:testDeleni
Failed asserting that 1 matches expected 2.
#1  C:\Users\David\PhpstormProjects\Kalkulacka\tests\unit\KalkulackaTest.php:44
#2  KalkulackaTest->testDeleni

---------
2) KalkulackaTest: Deleni vyjimka
 Test  tests\unit\KalkulackaTest.php:testDeleniVyjimka
Failed asserting that exception of type "InvalidArgumentException" is thrown.

FAILURES!
Tests: 5, Assertions: 11, Failures: 2.

Process finished with exit code 1 at 19:35:07.
Execution time: 490 ms.

Vidíme, že chyba je zachytená a sme na ňu upozornení. Neprešiel ako test delenia, tak test vyvolanie výnimky. Môžeme kód vrátiť späť do pôvodného stavu.

V budúcej lekcii, PHPUnit DataProvider a BestPractices , si ukážeme vybrané zdrojové kódy zaujímavých unit testov komerčných systémov, aby ste získali prehľad ako testovať zložitejšie situácie.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 76x (1.29 MB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP

 

Predchádzajúci článok
Úvod do unit testov v PHP a inštalácia PHPUnit
Všetky články v sekcii
Testovanie v PHP
Preskočiť článok
(neodporúčame)
PHPUnit DataProvider a BestPractices
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity