Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Jak mockovat final třídy?

Jak mockovat třídy, které jsou definované jako final nebo některé z jejich metod jsou final?

Mockání znamená nahrazení původního objektu za jeho testovací imitaci, která neprovádí žádnou funkcionalitu a jen se tváří jako původní objekt. A předstírá chování, které potřebujeme kvůli testování.

Takže například místo objektu PDO s metodami jako query() apod. vytvoříme jeho mock, který práci s databází jen předstírá, a místo toho ověřuje, že se volají ty správné SQL příkazy atd. Více třeba v dokumentaci Mockery.

A aby bylo možné mock předávat metodám, které mají type hint PDO, je potřeba, aby i třída mocku dědila od PDO. A to může být kámen úrazu. Pokud by totiž třída PDO nebo metoda query() byla final, už by to nebylo možné.

Existuje nějaké řešení? První možnost je final vůbec nepoužívat. To ovšem nepomůže s kódem třetích stran, který final používá, ale hlavně se tím ochuzujeme o důležitý prvek objektového návrhu. Existuje dogma, že každá třída by měla být buď final, nebo abstract.

Druhou a velmi šikovnou možností je použít Nette Tester, který od verze 2.0 disponuje vychytávkou, která odstraňuje z kódu klíčové slovo final on-the-fly. Stačí na začátku testu zavolat:

require __DIR__ . '/vendor/autoload.php';

Tester\Environment::bypassFinals();

A je to. Je za tím ukrytá neskutečně černá magie :-)

Pokud nepoužíváte Nette Tester, ale třeba PHPUnit, nebudete ochuzeni, stačí si nainstalovat BypassFinals:

composer require dg/bypass-finals --dev

A na začátku skriptu zavoláte:

require __DIR__ . '/vendor/autoload.php';

DG\BypassFinals::enable();

Komentáře

  1. SendiMyrkr #1

    avatar

    Není tam pak problém, že když z ne-final metody udělám final metodu, tak se při testech jejích potomků nedozvím, že je tam chyba?

    před 2 měsíci | odpovědět
  2. Svaťa Šimara #2

    avatar

    Toto řešení mi přijde dost ujeté. Zkusím paralelu s testováním private metod – jde to zařídit, ale pokud testuju privátní metody, dělám něco špatně. Stejně tak pokud mockuju final třídu, dělám něco špatně.

    …nepomůže s kódem třetích stran…

    Kód třetí strany do svého zaintegruji pomocí vlastního adaptéru

    před 2 měsíci | odpovědět | reagoval [3] taco
  3. taco #3

    avatar

    #2 Svaťo Šimaro, To přirovnání mi nesedí. Privátní metoda deiure neexistuje, proto ji nemohu testovat. Final třída je final proto, že autor architektury zavrhuje vytvářet specializované verze té třídy. Jenže mockování třídy asi nebude to o co autorovi šlo. (Viz v článku odkazované dogma.)

    před 2 měsíci | odpovědět | reagoval [4] Svaťa Šimara
  4. Svaťa Šimara #4

    avatar

    #3 taco, Ovlivňuje testování návrh kódu? Pokud budeme nejdříve psát testy a až poté implementaci, pak ano. V testech se nejdříve rozhodnu něco mocknout, pak jdu do implementace, kde mockování zakážu. No, a pak v duchu „protože to jde“ začnu hackovat problémy, které jsem si právě zařídil.

    Dogmata… Výše zmiňované dogma zase za pár let opustíme, protože se neukáže praktické.

    Ale abych se vrátil k myšlence proč mi to přijde ujeté. Mockujme pouze rozhraní a máme po problémech. Tím ale nemyslím mít proboha na všechno rozhraní. Prostě v testech tam, kde to bude potřeba, použiju daný objekt, jinde mock rozhraní.

    před 2 měsíci | odpovědět
  5. v6ak https://v6ak.com/ #5

    Bude to fungovat, když všechny výskyty slova “final” budou psány s alespoň jedním písmenem velkým? Co jsem projel zdroják, tak IMHO ne, strpos selže a soubor to nijak nemodifikuje.

    před 25 dny | odpovědět

Zanechat komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--

phpFashion © 2004, 2017 David Grudl | o blogu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.