PHPUnit: jak poprawnie używać covers do nawigacji i pokrycia testowego
Testowanie kontrolerów sieciowych w PHP często sprawia trudności z nawigacją między testami a kodem aplikacji. Przyjrzyjmy się, jak adnotacje i atrybuty covers w PHPUnit pomagają rozwiązać ten problem, poprawiając rozwój bez uszczerbku dla pokrycia.
Problem nawigacji między testem a kodem
Podczas testowania kontrolerów poprzez żądania HTTP bezpośrednie wywołanie metod jest niemożliwe, co utrudnia przejście od testu do odpowiedniego kodu. Na przykład, test sprawdza punkt końcowy /hello, ale nie odnosi się bezpośrednio do metody GreetingController::hello(). To prowadzi do ręcznego przeszukiwania w IDE, co spowalnia rozwój.
Przykład kontrolera i testu:
final class GreetingController extends AbstractController
{
#[Route('/hello')]
public function hello(): Response
{
return new Response($this->generate("Hello!"));
}
}
class GreetingControllerTest extends WebTestCase
{
public function test_hello(): void
{
$content = get('/hello');
assert_starts_with('Hello!', $content);
}
}
Trzy podejścia do łączenia testów z kodem
Deweloperzy stosują różne metody, aby poprawić nawigację.
1. Natywna składnia z refleksją
Zastępowanie ścieżek tekstowych wywołaniami metod poprzez refleksję, na przykład request(GreetingController::hello(...)). Wada: traci się niezależność testu od kodu aplikacji, co może prowadzić do błędów przy zmianach.
2. Adnotacja @see
Używanie adnotacji PHPDoc do wskazania połączenia:
/**
* @see \App\Controller\GreetingController::hello()
*/
public function test_hello(): void { ... }
Plusy: wsparcie w IDE. Minusy: wymaga pełnej ścieżki do klasy, uniwersalny tag bez wyspecjalizowanego wsparcia.
3. Wyspecjalizowane covers w PHPUnit
Adnotacje lub atrybuty stworzone do zarządzania pokryciem testowym i nawigacją.
Praca z adnotacjami covers w PHPUnit
Do PHPUnit 12 używano adnotacji @coversDefaultClass i @covers:
/**
* @coversDefaultClass \App\Controller\GreetingController
*/
class GreetingControllerTest extends WebTestCase
{
/**
* @covers ::hello
*/
public function test_hello(): void { ... }
}
Zalety:
- Doskonałe wsparcie w PhpStorm: autouzupełnianie, przejścia, wykrywanie użyć.
- Konfigurowalne szablony do generowania testów.
Wady szablonów w PhpStorm:
- Ograniczenie do dwóch szablonów dla PHPUnit.
- Zamieszanie w nazwach szablonów.
- Okresowe awarie w generatorze testów.
Przejście na atrybuty covers w PHPUnit 12+
PHPUnit 12 zastąpił adnotacje atrybutami, ale z ograniczeniem: można je stosować tylko do klas, a nie do metod.
Podstawowe użycie:
#[CoversClass('App\Controller\GreetingController')]
class GreetingControllerTest extends WebTestCase
{
public function test_hello(): void { ... }
}
To zmniejsza precyzję nawigacji, ponieważ nie wskazuje się konkretnej metody.
Wskazywanie metod poprzez CoversMethod:
#[CoversMethod('App\Controller\GreetingController', 'hello')]
#[CoversMethod('App\Controller\GreetingController', 'bye')]
class GreetingControllerTest extends WebTestCase
{
public function test_hello(): void { ... }
public function test_bye(): void { ... }
}
Wada: "girlanda" atrybutów przy testowaniu wielu metod.
Optymalna strategia: jedna metoda — jedna klasa testowa
Tworzenie oddzielnych klas testowych dla każdej metody upraszcza strukturę:
#[CoversMethod('App\Controller\GreetingController', 'hello')]
class HelloTest extends WebTestCase
{
public function test_hello(): void { ... }
public function test_hello2(): void { ... }
}
Zalety:
- Zmniejszenie obciążenia kognitywnego.
- Nie trzeba dodawać covers dla każdej metody testowej.
- Wspieranie czystego projektu: jeden kontroler — jeden punkt końcowy.
Konfiguracja szablonów dla atrybutów jest podobna do adnotacji, ale wymaga ręcznego przeniesienia CoversMethod do klasy po generacji.
Integracja z IDE i przyszłe ulepszenia
PhpStorm już wspiera przejście od metody testowej do testowanej klasy przez Ctrl+Shift+T. Oczekiwane jest rozszerzenie funkcjonalności dla bezpośredniego przejścia do metod.
Co jest ważne
- Używaj covers, aby poprawić nawigację, ale pamiętaj o ich wpływie na pokrycie.
- Atrybuty w PHPUnit 12+ są stosowane tylko do klas, co wymaga adaptacji strategii testowania.
- Optymalne podejście — jedna klasa testowa na metodę dla uproszczenia utrzymania.
- Skonfiguruj szablony w IDE do automatycznego generowania covers.
- Śledź aktualizacje PhpStorm dla lepszego wsparcia atrybutów.
Ograniczenie pokrycia jako główna wada covers
Pierwotnym celem covers jest ograniczenie pokrycia testowego do ram klasy lub metody. Na przykład, CoversClass wyklucza z raportu kod poza klasą. To przydatne w rygorystycznych projektach, ale większości deweloperów ważniejsze jest widzenie niepokrytych części kodu.
Próby wyłączenia covers:
- Przeciążona metoda: Skrypty do usuwania znaczników przed uruchomieniem testów.
- Praktyczna metoda: Łatanie phpunit/php-code-coverage poprzez Composer.
Wybór podejścia zależy od wymagań projektu i preferencji zespołu.
— Editorial Team
Brak komentarzy.