Jednotkové testování v PHP: možnosti při psaní testovacích případů

10. 11. 2021
Doba čtení: 14 minut

Sdílet

 Autor: Depositphotos
V pokračování se dozvíme, jaké PHPUnit poskytuje možnosti při psaní testovacích případů. Základní možnosti (z dostupných 120) jsou vysvětleny na příkladech. Opět se dozvíme o dalších možnostech spolupráce PHPUnit a PhpStorm.

7. Základní možnosti při psaní testovacích případů

PHPUnit nám dává široké možnosti při vytváření testovacích případů. Máme k dispozici tři základní sady možností:

  1. použití různých assertXY() metod ze třídy PHPUnit\Framework\Assert ve smyslu rovnosti / nerovnosti
  2. testování vyhození / nevyhození výjimek
  3. definování akcí, které mají běžet před spuštěním celého testu a i jednotlivých testovacích případů a po jejich ukončení

Je zcela běžné, že testovací třída obsahuje více testovacích případů – podrobně viz dále. Pak se nazývá testovací sada (test suite [swi:t]).

7.1. Testovací metody z PHPUnit\Framework\Assert

Třída PHPUnit\Framework\TestCase dědí od třídy  PHPUnit\Framework\Assert, takže může využívat všechny dále zmiňované metody. Z důvodů přehlednosti bude v souvislosti s assert metodami zmiňována rodičovská třída PHPUnit\Framework\Assert.

Třída PHPUnit\Framework\Assert dává k dispozici značné množství assert metod (více než 100). Všechny poskytují výsledek podle stejného principu:

  • V případě selhání (tj. assert nevyhověl) zajistí, že je vyhozena výjimka ExpectationFailedException a je vygenerována informace o selhání.
  • V případě úspěchu se neděje nic, což znamená, že testovací případ prošel bez problémů.

Assert metody jsou statické, ovšem v kombinaci se třídou PHPUnit\Framework\TestCase je lze volat i jako instanční. To umožňuje dva rovnocenné způsoby volání:

  • $this->assertEquals(2, $predmet->getZnamka());
  • self::assertEquals(2, $predmet->getZnamka());

Poznámka:
Je třeba si zvolit jeden z nich a ten důsledně používat. Běžnější způsob je $this->assert.

Každá assert metoda má přetíženou verzi se zadanou chybovou zprávou pro generování případné dodatečné informace o důvodu selhání. Tuto dodatečnou informaci typu string přidává programátor testovacího případu. Doporučuje se tuto možnost používat.

Ovšem informace o tom, proč aserce neprošla, je vypsána i při použití assert metody bez zprávy. Rozdíly v chybové zprávě budou patrné z následujícího příkladu.

<?php

namespace app\zaklad;

use app\zaklad\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetuTestZprava extends TestCase
{
  public function testSetZnamka_BezZpravy() : void
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $predmet->setZnamka(3);
    $this->assertEquals(2, $predmet->getZnamka());
  }

  public function testSetZnamka_SeZpravou() : void
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $predmet->setZnamka(3);
    $this->assertEquals(2, $predmet->getZnamka(), "Vracena hodnota znamky je chybna: ");
  }
}

Vypíše:

1) testSetZnamka_BezZpravy()
Failed asserting that 3 matches expected 2.
Expected :2
Actual   :3

2) testSetZnamka_SeZpravou()
Vracena hodnota znamky je chybna:
Failed asserting that 3 matches expected 2.
Expected :2
Actual   :3

Pokud chceme programově způsobit selhání testu (praktické použití viz dále), použijeme motodu fail() nebo fail(string : chybová_zpráva)

Poznámka:
PHPUnit ve verzi 9.5 dává k dispozici 60 různých assert metod. K nim přibývají vždy ještě jejich „Not“ verze. Například assertEquals() a assertNotEquals(). A samozřejmě vždy i jejich přetížené verze s dodatečnou zprávou.

7.1.1. Testy rovnosti

Jedná se o základní a nejčastější typ assert metody přetížené pro všechny datové typy. Vždy platí, že rovnají-li se hodnoty, test prošel.

assertEquals(datový_typ očekávanáHodnota, datový_typ skutečnáHodnota)

Pro nerovnost lze použít assertNotEquals().

Pokud porovnáváme reálná čísla, tj. typy double nebo float, použijeme verzi s tolerancí přesnosti:

class DoubleTest extends TestCase
{
  public function testPresnost_OK()
  {
    $this->assertEqualsWithDelta(pi(), 3.14, 0.01);
  }

  public function testPresnost_Chyba()
  {
    $this->assertEqualsWithDelta(pi(), 3.14, 0.0001, "Presnost na 0.0001");
  }
}

Pro druhý testovací případ vypíše:

Presnost na 0.0001
Failed asserting that 3.14 matches expected 3.141592653589793.
Expected :3.1415926535898
Actual   :3.14

Testy rovnosti lze použít i pro porovnávání objektů. Pozor však na to, že testy rovnosti jsou jiné, než testy shodnosti assertSame()  – viz dále.

7.1.2. Testy logické hodnoty

  assertFalse(bool skutečnáLogickáHodnota)
  assertTrue(bool skutečnáLogickáHodnota)

Tyto metody jsou často (nevhodně) nahrazovány předchozím asertem:
assertEquals(true/false, skutečnáLogickáHodnota)

7.1.3. Testy shodnosti

assertSame(mixed $expected, mixed $actual)
assertNotSame(mixed $expected, mixed $actual)

U těchto metod musejí mít porovnávané veličiny stejný typ a stejnou hodnotu.

class SameTest extends TestCase
{
  public function testRovnost_OK()
  {
    $this->assertEquals("3.14", 3.14);
  }

  public function testShodnost_Chyba()
  {
    $this->assertSame("3.14", 3.14);
  }
}

Po spuštění testRovnost_OK() projde. Ale testShodnost_Chyba() selže a vypíše:
Failed asserting that 3.14 is identical to '3.14'

7.1.4. Testy řetězců

Řetězce se dají samozřejmě porovnávat na rovnost pomocí obecné assertEquals().

V této skupině jsou uvedeny assert metody určené speciálně pro řetězce, přičemž názvy metod jsou dostatečně významové:

  • assertStringContainsString(string $cast, string $celek)
  • assertStringContainsStringIgnoringCase(string $cast, string $celek)
  • assertEqualsIgnoringCase(mixed $expected, mixed $actual)
  • assertStringStartsWith(string $prefix, string $string)
  • assertStringEndsWith(string $suffix, string $string)
  • assertMatchesRegularExpression(string $pattern, string $string)
  • assertStringMatchesFormat(string $format, string $string)
  • assertStringEqualsFile(string $expectedFile, string $actualString)

7.1.5. Testy datových typů

  • assertIsArray($actual)
  • assertIsBool($actual)
  • assertIsFloat($actual)
  • assertIsInt($actual)
  • assertIsNumeric($actual)
  • assertIsObject($actual)
  • assertIsString($actual)
  • assertIsIterable($actual)

7.1.6. Testy adresářů a souborů

  • assertDirectoryExists(string $directory)
  • assertDirectoryIsReadable(string $directory)
  • assertDirectoryIsWritable(string $directory)
  • assertFileEquals(string $expected, string $actual)
  • assertFileExists(string $filename)
  • assertFileIsReadable(string $filename)
  • assertFileIsWritable(string $filename)

7.1.7. Testy nerovností

  • assertGreaterThan(mixed $expected, mixed $actual)
  • assertGreaterThanOrEqual(mixed $expected, mixed $actual)
  • assertLessThan(mixed $expected, mixed $actual)
  • assertLessThanOrEqual(mixed $expected, mixed $actual)

7.1.8. Testy speciálních hodnot

  • assertEmpty(mixed $actual)
  • assertNull(mixed $variable)
  • assertNan(mixed $variable)
  • assertInfinite(mixed $variable)

7.1.9. Testy existence prvku v kontejneru

  • assertArrayHasKey(mixed $key, array $array)
  • assertContains(mixed $prvek, iterable $kontejner)
  • assertContainsOnly(string $type, iterable $kontejner)
  • assertCount($expectedCount, $kontejner)

7.1.10. Testy tříd a objektů tříd

  • assertClassHasAttribute(string $attributeName, string $className)
  • assertClassHasStaticAttribute(string $attributeName, string $className)
  • assertContainsOnlyInstancesOf(string $classname, array $seznam)
  • assertObjectEquals(object $expected, object $actual, string $method = 'equals')
  • assertContainsOnlyInstancesOf(string $classname, array $seznam)
  • assertInstanceOf($expected, $actual)
  • assertObjectHasAttribute(string $attributeName, object $object)

7.1.11. Testy formátů typu JSON a XML

  • assertJsonFileEqualsJsonFile(mixed $expectedFile, mixed $actualFile)
  • assertJsonStringEqualsJsonFile(mixed $expectedFile, mixed $actualJsonString)
  • assertJsonStringEqualsJsonString(mixed $expectedJson, mixed $actualJson)
  • assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile)
  • assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXmlString)
  • assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml)

7.2. Testy vyhození výjimek

V jednotkových testech potřebujeme někdy ověřit i vyhození očekávané výjimky. Toto se používá pro testování metod, které pracují s výjimkami, např. metoda setZnamka() ze třídy HodnoceniPredmetu.

/**
  * Nastavuje známku v rozsahu od VYBORNE do NEDOSTATECNE
  * @param znamka nastavovaná známka
  * @throws InvalidArgumentException pokud je známka mimo rozsah
  */
public function setZnamka(int $znamka) : void
{
  if ($znamka >= self::VYBORNE  &&  $znamka <= self::NEDOSTATECNE) {
    $this->znamka = $znamka;
  }
  elseif ($this->znamka === null  &&  $znamka == self::DOSUD_NEHODNOCENO) {
    // prvni nastaveni v konstruktoru
    $this->znamka = $znamka;
  }
  else {
    throw new \InvalidArgumentException($znamka);
  }
}

Pro test vyhození výjimky se používá expectException(jmenoVyjimky::class), která se uvádí před kódem, který výjimku vyvolá. Test – je to negativní test – projde, pokud je během něho vyhozena tato konkrétní výjimka. Test selže v ostatních případech, tj. vyhození jiné výjimky nebo nevyhození výjimky vůbec.

Pro speciálnější test výjimky se používá expectExceptionMessage(string $zprava), kdy test projde, pokud je během něho vyhozena výjimka generující danou zprávu. A test neprojde v ostatních případech, tj. výjimka generuje jinou zprávu nebo výjimka není vůbec vyhozena.

Poznámka:
V případech 2. a 3. je porušeno pravidlo, že „testujeme aby test prošel“. Tyto testovací případy jsou napsány tak, aby bylo možné ověřit, jak vypadá selhání testu. Proto jejich název končí na Chyba. Případy 1. a 4. z tohoto důvodu končí na OK, byť je to zbytečné (je to očekávaný způsob testování) a běžně toto označení nepoužíváme.

// 1. testSetZnamka_Vyjimka_OK()
– testuje přímo výjimku InvalidArgumentException, která je metodou vyhazována při nesprávné hodnotě parametru znamka (zde hodnota 8)
– test projde
// 2. testSetZnamka_Vyjimka_Chyba()
– testuje přímo výjimku InvalidArgumentException, která ale zde není metodou vyhazována, protože hodnota parametru znamka je správná (zde hodnota 1)
– test selže, je vypsáno:
Failed asserting that exception of type "InvalidArgumentException" is thrown.
// 3. testSetZnamka_JinaVyjimka_Chyba()
– testuje úplně jinou výjimku OutOfRangeException, která ale není metodou vyhazována, ačkoliv je nesprávná hodnota parametru znamka (zde hodnota  8)
– test selže, je vypsáno:
  Failed asserting that exception of type "InvalidArgumentException"
  matches expected exception "OutOfRangeException". Message was: "8"
// 4. testSetZnamka_VyjimkaZprava_OK()
– pomocí metody expectExceptionMessage() testuje zprávu vyhozenou výjimkou InvalidArgumentException, která je metodou vyhazována při nesprávné hodnotě parametru znamka (zde hodnota  8)
– test projde

Testovací třída má obsah:

class VyjimkyTest extends TestCase
{
  // 1.
  public function testSetZnamka_Vyjimka_OK()
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $this->expectException(\InvalidArgumentException::class);
    $predmet->setZnamka(8);
  }

  // 2.
  public function testSetZnamka_Vyjimka_Chyba()
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $this->expectException(\InvalidArgumentException::class);
    $predmet->setZnamka(1);
  }

  // 3.
  public function testSetZnamka_JinaVyjimka_Chyba()
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $this->expectException(\OutOfRangeException ::class);
    $predmet->setZnamka(8);
  }

  // 4.
  public function testSetZnamka_VyjimkaZprava_OK()
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $this->expectExceptionMessage("8");
    $predmet->setZnamka(8);
  }
}

7.3. Akce před a po spuštění testovacích případů

Pro testování metod jedné třídy nebo i jedné metody používáme běžně více testovacích případů – pozitivní i negativní testy. Opakované testování ale s sebou nese problém, že by se často opakoval kód nastavení podmínek pro testovací případ. Tím by docházelo k porušení principu DRY (Don't Repeat Yourself).

Tento neblahý stav lze laicky vyřešit např. umístěním společného „nastavovacího“ kódu do samostatné privátní metody, zde nastaveni().

<?php

namespace app\fixture;

use app\zaklad\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetuTestOpakovane extends TestCase
{
  private $predmet;

  private function nastaveni() : void
  {
    $this->predmet = new HodnoceniPredmetu("Matika");
    $this->predmet->setZnamka(1);
  }

  public function testSetZnamka() : void
  {
    $this->nastaveni();
    $this->assertEquals(1, $this->predmet->getZnamka());
  }

  public function testIsNehodnoceno() : void
  {
    $this->nastaveni();
    $this->assertFalse($this->predmet->isNehodnoceno());
  }
}

PHPUnit umožňuje toto opakované nastavování (test fixture) vyřešit mnohem elegantněji. Kód lze zjednodušit pomocí čtyř metod se speciálními jmény:

  1. public static function setUpBeforeClass() : void

    Provede se jednou před spuštěním všech testovacích případů této třídy. To je výhodné pro nastavení všech případných statických proměnných – typicky je to připojení do databáze nebo nastavení driveru.

  2. public static function tearDownAfterClass() : void

    Provede se jednou po skončení všech testovacích případů této třídy, což je výhodné pro závěrečný „úklid“ nebo pro statistiku testu.

  3. public function setUp() : void

    Provede se před spuštěním každého testovacího případu. Výhodné pro opakované nastavení testovaného objektu u každého testovacího případu.

  4. public function tearDown() : void

    Provede se po ukončení každého testovacího případu – výhodné pro průběžný „úklid“.

Ukázka využití jednotného nastavování – příklad má stejnou funkčnost jako předchozí příklad. Navíc jsou v něm jen informační výpisy na konzoli.

<?php

namespace app\fixture;

use app\zaklad\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetuTest_Fixture extends TestCase
{
  private $predmet;

  public static function setUpBeforeClass() : void
  {
    fwrite(STDOUT, "Před všemi testovacími případy\n");
  }

  public static function tearDownAfterClass() : void
  {
    fwrite(STDOUT, "Po všech testovacích případech\n");
  }

  public function setUp() : void
  {
    fwrite(STDOUT, "  Před každým testovacím případem\n");
    $this->predmet = new HodnoceniPredmetu("Matika");
    $this->predmet->setZnamka(1);
  }

  public function tearDown(): void
  {
    fwrite(STDOUT, "  Po každém testovacím případu\n");
  }

  public function testSetZnamka() : void
  {
    fwrite(STDOUT, "    1.testovací případ\n");
    $this->assertEquals(1, $this->predmet->getZnamka());
  }

  public function testIsNehodnoceno() : void
  {
    fwrite(STDOUT, "    2.testovací případ\n");
    $this->assertTrue($this->predmet->isNehodnoceno());
  }
}

První test projde, druhý plánovaně selže – to ukazuje že tearDown() funguje vždy – a vypíše se:

Před všemi testovacími případy
  Před každým testovacím případem
    1.testovací případ
  Po každém testovacím případu
  Před každým testovacím případem
    2.testovací případ
  Po každém testovacím případu

Failed asserting that false is true.

Po všech testovacích případech

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

8. Organizace více testovacích případů

Je zcela běžné, že testovací třída obsahuje více testovacích případů (test case) a tím se z ní stává testovací sada (test suite). U testované třídy se testují všechny potřebné (viz dále) metody třídy a konstruktor. Navíc se každá metoda či konstruktor testují pomocí více testovacích případů, což je výhodné ze dvou základních pohledů. Za prvé – testovací metody mohou být dostatečně jednoduché, tj. přehledné a snadno upravovatelné. A za druhé – mohou se vždy zaměřit jen na jednu testovanou vlastnost.

Dohromady jsou všechny testovací případy uloženy v jedné třídě a spuštění testů znamená spuštění všech testů dané testovací třídy.

Pokud je testovaná třída rozsáhlá, lze mít víc tříd testů na jednu testovanou třídu. To nijak nevadí z testerského pohledu, ale z návrhářského pohledu je to často signál, že třída má víc různých zodpovědností.
V každém případě pak existuje několik tříd testů, u kterých je nutno zajistit, aby bylo v případě potřeby možné najednou je všechny spustit – viz dále.

Varování:
Pokud budeme mít v PhpStorm v jednom adresáři více tříd testů a budeme je chtít spouštět všechny najednou (viz dále) musí jména těchto tříd končit na Test, např. HodnoceniPredmetu_KonstruktorTest. Pokud budou pojmenovány jinak, např. HodnoceniPredmetuTest_Konstruktor, půjdou spustit jednotlivě, jako třídy, ale nepůjdou spustit společně.

8.1. Ukázka sady testů entitní třídy

V ukázce budeme testovat tutéž třídu HodnoceniPredmetu, která je nyní ve jmenném prostoru skutecnytest. Aby nebylo nutné hledat její zdrojový kód v dřívějších částech, je zde uveden znovu.

<?php
namespace app\skutecnytest;

class HodnoceniPredmetu
{
  // konstanty pro známkování
  const VYBORNE = 1;
  const NEDOSTATECNE = 5;
  const DOSUD_NEHODNOCENO = 0;
  const DOSUD_NEHODNOCENO_SLOVY = "N/A";

  private $nazev;
  private $znamka;

  public function __construct(string $nazev, int $znamka=self::DOSUD_NEHODNOCENO)
  {
    $this->nazev = $nazev;
    $this->setZnamka($znamka);
  }

  public function getNazev() : string
  {
    return $this->nazev;
  }

  public function getZnamka() : int
  {
    return $this->znamka;
  }

  /**
   * Nastavuje známku v rozsahu od VYBORNE do NEDOSTATECNE
   * @param znamka nastavovaná známka
   * @throws InvalidArgumentException pokud je známka mimo rozsah
   */
  public function setZnamka(int $znamka) : void
  {
    if ($znamka >= self::VYBORNE  &&  $znamka <= self::NEDOSTATECNE) {
      $this->znamka = $znamka;
    }
    elseif ($this->znamka === null  &&  $znamka == self::DOSUD_NEHODNOCENO) {
     // prvni nastaveni v konstruktoru
     $this->znamka = $znamka;
    }
    else {
      throw new \InvalidArgumentException($znamka);
    }
  }

  /**
   * Zjistí, zda je předmět dosud nehodnocen
   * @return true, pokud je předmět nehodnocen
   */
  public function isNehodnoceno() : bool
  {
    return ($this->znamka == self::DOSUD_NEHODNOCENO);
  }

  public function __toString() : string
  {
    if ($this->isNehodnoceno() == true) {
      return $this->nazev . ": " . self::DOSUD_NEHODNOCENO_SLOVY . "<br>";
    }
    else {
      return $this->nazev . ": " . $this->znamka . "<br>";
    }
  }
}

Tato třída bude otestována testovacími případy rozdělenými do tří tříd (test suite), aby bylo později vidět, jak je možné spustit všechny tři najednou.

Poznámka:
Je nutné dodat, že zde rozdělení do více tříd nemá praktický smysl, protože testovacích případů je relativně málo. Pokud je testovacích případů málo, pak by v reálném případě byl význam dělení do více tříd nejspíše při potřebě mít různé metody setUp().

Poznámka:
Všechny uvedené testovací případy až na jeden projdou. Selže testKonstruktor_Znamka(), aby byl vidět způsob reakce PHPUnit a potažmo i PhpStorm na selhání.

Třída HodnoceniPredmetu_KonstruktorTest testuje správnou funkci konstruktorů. První testovací případ je víceméně zbytečný, protože se testuje pouze správnost přiřazovacího příkazu. Další dva testy již testují kontrakt.

<?php

namespace app\skutecnytest;

use app\skutecnytest\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetu_KonstruktorTest extends TestCase
{
  public function testKonstruktor_NazevPredmetu() : void
  {
    $predmet = new HodnoceniPredmetu("Matika", 5);
    $this->assertEquals("Matika", $predmet->getNazev());
  }

  public function testKonstruktor_Znamka() : void
  {
    $predmet = new HodnoceniPredmetu("Matika", 5);
    $this->assertEquals(2, $predmet->getZnamka());
  }

  public function testKonstruktor_ZnamkaNevyplnena() : void
  {
    $predmet = new HodnoceniPredmetu("Matika");
    $this->assertEquals(HodnoceniPredmetu::DOSUD_NEHODNOCENO, $predmet->getZnamka());
  }
}

Třída HodnoceniPredmetu_ZnamkaTest testuje všechny základní možnosti metody setZnamka().

<?php

namespace app\skutecnytest;

use app\skutecnytest\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetu_ZnamkaTest extends TestCase
{
  private $predmet;

  public function setUp() : void
  {
    $this->predmet = new HodnoceniPredmetu("Matika");
  }

  public function testSetZnamka_DolniMez() : void
  {
    $this->predmet->setZnamka(1);
    $this->assertEquals(1, $this->predmet->getZnamka());
  }

  public function testSetZnamka_HorniMez() : void
  {
    $this->predmet->setZnamka(5);
    $this->assertEquals(5, $this->predmet->getZnamka());
  }

  public function testSetZnamka_MimoMezeDolni() : void
  {
    $this->expectException(\InvalidArgumentException::class);
    $this->predmet->setZnamka(0);
  }

  public function testSetZnamka_MimoMezeHorni() : void
  {
    $this->expectException(\InvalidArgumentException::class);
    $this->predmet->setZnamka(6);
  }
}

Třída HodnoceniPredmetu_MetodyTest testuje zbylé dvě metody.
Z pedagogických důvodů jsou pro metodu isNehodnoceno() v jednom testovacím případu testovány oba stavy ( true, false). Pozor – tento způsob není vhodný. Smyslem xUnit testů je testovat co nejvíce jednoduchých (jednoznačných) příkladů, tj. jeden assert v jednom testovacím případu (viz též dříve pravidlo Arange – Act – Assert). Tento vhodný přístup byl v předchozí ukázce použit pro testy dolní a horní meze známky.

Dále je zde testována metoda __toString() a to již ve dvou nezávislých případech, což je vhodnější.

  <?php

namespace app\skutecnytest;

use app\skutecnytest\HodnoceniPredmetu;
use PHPUnit\Framework\TestCase;

class HodnoceniPredmetu_MetodyTest extends TestCase
{
  const NAZEV_PREDMETU = "Matika";
  private $predmet;

  public function setUp() : void
  {
    $this->predmet = new HodnoceniPredmetu(self::NAZEV_PREDMETU);
  }

  public function testIsNehodnoceno() : void
  {
    $this->assertTrue($this->predmet->isNehodnoceno());
    $this->predmet->setZnamka(HodnoceniPredmetu::VYBORNE);
    $this->assertFalse($this->predmet->isNehodnoceno());
  }

  public function testToString_Nehodnoceno() : void
  {
    $ocekavano = self::NAZEV_PREDMETU . ": " .
                 HodnoceniPredmetu::DOSUD_NEHODNOCENO_SLOVY . "<br>";

    $this->assertEquals($ocekavano, $this->predmet->__toString());
  }

  public function testToString_Hodnoceno() : void
  {
    $this->predmet->setZnamka(HodnoceniPredmetu::NEDOSTATECNE);
    $ocekavano = self::NAZEV_PREDMETU . ": " .
                 HodnoceniPredmetu::NEDOSTATECNE . "<br>";

    $this->assertEquals($ocekavano, $this->predmet->__toString());
  }
}

9. Praktické náležitosti

9.1. Kam se soubory testů fyzicky umísťují

Soubory testů se umísťují do jiného adresáře než testovaná třída, ale do stejného jmenného prostoru. Pro výše uvedený příklad bude výsledná adresářová struktura ze zeleně podbarvenými testy následující:


Autor: Pavel Herout

V textové podobě je struktura souborů a adresářů:

bitcoin_skoleni

  src
   app
      skutecnytest
         HodnoceniPredmetu.class.php

   test
      app
         skutecnytest
            HodnoceniPredmetu_KonstruktorTest.php
            HodnoceniPredmetu_MetodyTest.php
            HodnoceniPredmetu_ZnamkaTest.php 

9.2. Jak se spouští najednou testy z více testovacích souborů

Použijeme kontextové menu na adresáři test/app/skutecnytest, odkud můžeme najednou spustit všechny testy uložené v tomto adresáři.


Autor: Pavel Herout

Po spuštění testů dostaneme (vtestKonstruktor_Znamka()  je opět záměrná chyba, aby byl zřejmý způsob informace o selhání testu):


Autor: Pavel Herout

Autor článku

Pracuje na Katedře informatiky a výpočetní techniky Fakulty aplikovaných věd na Západočeské univerzitě v Plzni, zabývá se programovacími jazyky, softwarovými technologiemi a testováním.