Testování pravidel
RuleTester a formát fixtur: soubory .code, .expected a .violations, volby a verze PHP v hlavičce, a co všechno tester hlídá za vás.
Fixtury
Pravidlo se testuje nad adresářem fixtur, jedním na pravidlo. Každá fixtura jsou až tři soubory téhož jména:
basic.codeje kód před opravou;basic.expectedje kód po opravě; když chybí, pravidlo nesmí soubor změnit;basic.violationsjsou očekávaná hlášení, řádek a zpráva, každé na svém řádku:
3: The message of an exception must end with a period
6: The message of an exception must end with a period
Fixtura může na některém z prvních tří řádků nést volby pravidla jako JSON a verzi PHP, pro kterou je psaná:
<?php
// {"functions": ["dd", "dump"]}
// php 8.4
Bez verze se pravidlo testuje na své minPhpVersion, jinak na PHP 8.0; nikdy na verzi interpretu, který testy
spouští, protože verdikt pravidla má být na počítači nezávislý.
Fixtura není ukázka do dokumentace: má být ošklivá a plná hraničních případů. Komentář uprostřed konstrukce, konstrukce na jednom řádku i přes tři, prázdné tělo, interpolovaný řetězec, alternativní syntaxe. Právě tam se pravidla lámou.
RuleTester
use DressCode\Testing\RuleTester;
RuleTester::run(ExceptionMessagePeriodRule::class, __DIR__ . '/fixtures/exception-message-period');
run() projde všechny soubory *.code v adresáři a vrátí jejich počet; selhání je výjimka
DressCode\Testing\TestFailure se jménem fixtury a diffem, takže ji ukáže každý testovací framework. Z Nette
Testeru je to celý test, z PHPUnit je to jedno volání v testovací metodě.
Pro každou fixturu tester ověří:
- výstup se rovná
.expected(nebo vstupu, když.expectednení); - hlášení se rovnají
.violations, řádek po řádku a v pořadí; - idempotenci: pravidlo nad vlastním výstupem už nic nezmění ani neohlásí opravitelné porušení;
- komentáře: ve výstupu jsou všechny komentáře ze vstupu, pokud pravidlo neřekne
modifiesComments; - potlačení: s
dresscode:ignore-filev hlavičce pravidlo nic neohlásí ani nezmění; - kontrakt oprav: žádná změna stromu bez hlášení, které prošlo;
- strom: každý uzel má správného rodiče, což se rozbije při chybném vkládání.
Pravidlo, které volby dostává jinak než z konfigurace (třeba se závislostí v konstruktoru), předáte místo třídy
jako továrnu fn(array $options): Rule.
Menší nástroje pro zvláštní případy: RuleTester::runFixture() spustí jednu fixturu,
RuleTester::check() ověří pravidlo nad řetězcem bez souborů (hodí se pro test uvnitř dokumentace nebo pro
rychlou reprodukci), RuleTester::collectViolations() vrátí hlášení nad fixturou ve tvaru souboru
.violations, takže ho můžete nechat zapsat a jen zkontrolovat diff, místo abyste hlášení
opisovali ručně.
Spouštění celého nástroje
Test pravidla ověří pravidlo samotné. Jak se chová spolu s ostatními, ukáže až běh nad skutečným kódem:
dresscode check --strict-rules nad projektem udělá z každého porušeného kontraktu chybu místo varování, a
--jobs 1 běží v jednom procesu, kde se pohodlně ladí. Než pravidlo zveřejníte, pusťte fix nad
větším cizím kódem (třeba vendor/) a podívejte se na diff: idempotenci a komentáře hlídá tester,
vkus ne.