Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Unit Tests mit PHPUnit

Unit Tests mit PHPUnit

~17 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Zeit für automatisierte Qualitätssicherung – wir testen ProjectStatistikService aus Kapitel 33 ISOLIERT, OHNE echte Datenbank.

Das Test-Pack installieren

composer require --dev symfony/test-pack

Die Recipe (Kapitel 6) installiert PHPUnit UND legt phpunit.dist.xml sowie tests/bootstrap.php an.

Unit-Tests vs. funktionale Tests: der Unterschied

Test-ArtEigenschaften
Unit-Tests (dieses Kapitel)Testen EINE Klasse ISOLIERT, OHNE Datenbank, OHNE HTTP-Kernel – SCHNELL (Millisekunden), Abhängigkeiten werden durch Fakes/Mocks ersetzt.
Funktionale Tests (Kapitel 43)Testen das ZUSAMMENSPIEL mehrerer Komponenten über eine ECHTE HTTP-Anfrage – LANGSAMER, aber realistischer.

Den ersten Unit-Test schreiben

php bin/console make:test TestCase ProjectStatistikServiceTest
tests/Service/ProjectStatistikServiceTest.php
<?php

declare(strict_types=1);

namespace App\Tests\Service;

use App\Entity\Project;
use App\Repository\TaskRepository;
use App\Service\ProjectStatistikService;
use PHPUnit\Framework\TestCase;

class ProjectStatistikServiceTest extends TestCase
{
    public function testBerechneStatistikOhneAufgaben(): void
    {
        $taskRepository = $this->createMock(TaskRepository::class);
        $taskRepository->method('zaehleAufgabenNachStatus')->willReturn([]);

        $service = new ProjectStatistikService($taskRepository);
        $ergebnis = $service->berechneStatistik(new Project());

        self::assertSame(0, $ergebnis['offen']);
        self::assertSame(0.0, $ergebnis['fortschritt']);
    }

    public function testBerechneStatistikMitFortschritt(): void
    {
        $taskRepository = $this->createMock(TaskRepository::class);
        $taskRepository->method('zaehleAufgabenNachStatus')->willReturn([
            ['status' => 'erledigt', 'anzahl' => 3],
            ['status' => 'offen', 'anzahl' => 1],
        ]);

        $service = new ProjectStatistikService($taskRepository);
        $ergebnis = $service->berechneStatistik(new Project());

        self::assertSame(75.0, $ergebnis['fortschritt']);
    }
}

createMock(TaskRepository::class) erzeugt ein FAKE-Repository, das NIEMALS eine echte Datenbank berührt – method(...)->willReturn(...) definiert, WAS die Fake-Methode zurückgeben soll, wenn sie aufgerufen wird. GENAU DAS ist der praktische Wert von Dependency Injection aus Kapitel 32: ProjectStatistikService weiß NICHT, ob es mit einem echten oder einem Fake-Repository arbeitet.

Die Tests ausführen

php bin/phpunit
php bin/phpunit tests/Service/ProjectStatistikServiceTest.php  # nur eine Datei
php bin/phpunit --filter testBerechneStatistikMitFortschritt   # nur eine Methode

Wichtige Assertions im Überblick

  • assertSame($erwartet, $tatsaechlich) – strikte Gleichheit (===), IMMER bevorzugen gegenüber assertEquals().
  • assertTrue(...)/assertFalse(...) – Boolean-Prüfung.
  • assertCount($anzahl, $array) – Array-/Collection-Länge.
  • assertInstanceOf(Klasse::class, $objekt) – Typ-Prüfung.
  • expectException(Klasse::class) – erwartet, dass eine bestimmte Exception geworfen wird.
public function testWirftFehlerBeiUngueltigemStatus(): void
{
    $this->expectException(\InvalidArgumentException::class);

    $aufgabe = new Task();
    $aufgabe->setStatus('ungueltiger-status');
}

Test Coverage messen

php bin/phpunit --coverage-html var/coverage

Erzeugt einen HTML-Bericht, der ZEILENGENAU zeigt, welcher Code von Tests abgedeckt ist – NÜTZLICH, um blinde Flecken zu finden, aber KEIN Selbstzweck: 100% Coverage garantiert NICHT automatisch fehlerfreien Code, nur dass jede Zeile MINDESTENS EINMAL ausgeführt wurde.

Tipp: Faustregel: Unit-Tests eignen sich HERVORRAGEND für Services mit klarer, isolierbarer Logik wie ProjectStatistikService – für Code, der stark von der Datenbank oder dem HTTP-Kontext abhängt (Controller, Repositories selbst), sind funktionale Tests (Kapitel 43) oft der PASSENDERE Ansatz.