Testování pravidel
RuleTester a formát fixtur: soubory .code, .expected a
.violations, volby a cílová verze PHP v hlavičce fixtury, a co všechno tester ohlídá za vás.
Fixtury
Pravidlo se testuje nad adresářem fixtur, jedním na pravidlo. Fixtura (fixture) je až trojice souborů se stejným jménem:
basic.codeje kód před opravou;basic.expectedje kód po opravě; když soubor chybí, pravidlo nesmí kód změnit;basic.violationsjsou očekávaná hlášení, každé na svém řádku ve tvaru řádek a zpráva:
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 uvedené verze se pravidlo testuje na verzi ze své minPhpVersion, jinak na PHP 8.0. Nikdy ne 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ě na těchhle místech se pravidla lámou.
RuleTester
use DressCode\Testing\RuleTester;
RuleTester::run(ExceptionMessagePeriodRule::class, __DIR__ . '/fixtures/exception-message-period');
Metoda 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 s diffem, takže ji srozumitelně ukáže každý
testovací framework. Z Nette Testeru je tohle celý test, z PHPUnit je to jedno volání v testovací metodě.
U každé fixtury tester ověří:
- výstup se rovná souboru
.expected(nebo vstupu, když.expectednení); - hlášení se rovnají souboru
.violations, řádek po řádku a ve stejném 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 nemá
modifiesComments; - potlačení: s komentářem
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.
Pro zvláštní případy jsou tu menší nástroje: RuleTester::runFixture() spustí jedinou fixturu,
RuleTester::check() ověří pravidlo nad řetězcem bez souborů (hodí se na rychlou reprodukci) a
RuleTester::collectViolations() vrátí hlášení nad fixturou přímo ve tvaru souboru .violations,
takže si ho můžete nechat zapsat a jen zkontrolovat diff, místo abyste hlášení opisovali ručně.
Zkouška v reálném provozu
Test pravidla ověří pravidlo samotné. Jak se chová ve společnosti ostatních, ukáže až běh nad skutečným kódem.
Přepínač dresscode check --strict-rules udělá z každého porušeného kontraktu chybu místo varování a
--jobs 1 nechá všechno běžet v jediném procesu, kde se pohodlně ladí.
Než pravidlo zveřejníte, pusťte fix nad větším cizím kódem, třeba nad adresářem vendor/,
a projděte si diff. Idempotenci a komentáře ohlídá tester, vkus ne.