Powrót do strony głównej

PHPUnit covers: nawigacja i pokrycie testów dla deweloperów

Artykuł wyjaśnia, jak używać adnotacji i atrybutów covers w PHPUnit do poprawy nawigacji między testami a kodem aplikacji. Omówiono podejścia do powiązywania testów z metodami, konfigurację IDE i ograniczenia pokrycia.

Poprawiamy testowanie w PHP: przewodnik po covers w PHPUnit
Advertisement 728x90

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:

Google AdInline article slot
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.

Google AdInline article slot

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.

Google AdInline article slot

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

Advertisement 728x90

Czytaj dalej