PHPUnit: Unit Testing für PHP | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Unit Testing PHPUnit Grundlagen

Zuletzt aktualisiert: 20.01.2026 um 10:04 Uhr

PHPUnit: Unit Testing für PHP

Tests sind kein Luxus, sondern Notwendigkeit. Mit PHPUnit schreiben Sie automatisierte Tests, die Bugs verhindern und Refactoring ermöglichen.

Installation

# Als Dev-Dependency
composer require --dev phpunit/phpunit

# Version prüfen
./vendor/bin/phpunit --version

Projektstruktur

projekt/
├── src/
│   ├── Calculator.php
│   └── User.php
├── tests/
│   ├── CalculatorTest.php
│   └── UserTest.php
├── composer.json
└── phpunit.xml

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <coverage>
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
</phpunit>

Erster Test

Zu testende Klasse

<?php
// src/Calculator.php

namespace App;

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }

    public function divide(int $a, int $b): float
    {
        if ($b === 0) {
            throw new \InvalidArgumentException('Division durch Null');
        }
        return $a / $b;
    }
}

Test-Klasse

<?php
// tests/CalculatorTest.php

namespace Tests;

use App\Calculator;
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    private Calculator $calculator;

    protected function setUp(): void
    {
        $this->calculator = new Calculator();
    }

    public function testAddReturnsCorrectSum(): void
    {
        $result = $this->calculator->add(2, 3);

        $this->assertEquals(5, $result);
    }

    public function testAddWithNegativeNumbers(): void
    {
        $this->assertEquals(-1, $this->calculator->add(2, -3));
    }

    public function testDivideReturnsCorrectResult(): void
    {
        $this->assertEquals(2.5, $this->calculator->divide(5, 2));
    }

    public function testDivideByZeroThrowsException(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage('Division durch Null');

        $this->calculator->divide(10, 0);
    }
}

Tests ausführen

# Alle Tests
./vendor/bin/phpunit

# Bestimmte Datei
./vendor/bin/phpunit tests/CalculatorTest.php

# Bestimmter Test
./vendor/bin/phpunit --filter testAddReturnsCorrectSum

# Mit Coverage-Report
./vendor/bin/phpunit --coverage-html coverage/

Assertions

Assertion Prüft
assertEquals($expected, $actual) Werte sind gleich
assertSame($expected, $actual) Identisch (Typ + Wert)
assertTrue($condition) Ist true
assertFalse($condition) Ist false
assertNull($value) Ist null
assertNotNull($value) Ist nicht null
assertCount($count, $array) Array hat n Elemente
assertContains($needle, $haystack) Array enthält Wert
assertInstanceOf($class, $object) Objekt ist Instanz von
assertEmpty($value) Ist leer

Data Providers

Mehrere Testfälle mit unterschiedlichen Daten:

<?php
class CalculatorTest extends TestCase
{
    /**
     * @dataProvider additionProvider
     */
    public function testAdd(int $a, int $b, int $expected): void
    {
        $calculator = new Calculator();
        $this->assertEquals($expected, $calculator->add($a, $b));
    }

    public static function additionProvider(): array
    {
        return [
            'positive numbers' => [1, 2, 3],
            'negative numbers' => [-1, -2, -3],
            'mixed numbers'    => [-1, 2, 1],
            'with zero'        => [5, 0, 5],
        ];
    }
}

Mocking

<?php
class UserServiceTest extends TestCase
{
    public function testCreateUserSendsEmail(): void
    {
        // Mock erstellen
        $emailService = $this->createMock(EmailService::class);

        // Erwartung definieren
        $emailService->expects($this->once())
            ->method('send')
            ->with(
                $this->equalTo('user@example.com'),
                $this->stringContains('Willkommen')
            );

        // Service mit Mock testen
        $userService = new UserService($emailService);
        $userService->createUser('user@example.com', 'password');
    }
}

Setup und Teardown

<?php
class DatabaseTest extends TestCase
{
    private PDO $db;

    // Vor jedem Test
    protected function setUp(): void
    {
        $this->db = new PDO('sqlite::memory:');
        $this->db->exec('CREATE TABLE users (id INTEGER, name TEXT)');
    }

    // Nach jedem Test
    protected function tearDown(): void
    {
        $this->db = null;
    }

    // Einmal vor allen Tests
    public static function setUpBeforeClass(): void
    {
        // z.B. Test-Datenbank erstellen
    }

    // Einmal nach allen Tests
    public static function tearDownAfterClass(): void
    {
        // z.B. Aufräumen
    }
}

Test-Kategorien mit Gruppen

<?php
class SlowTest extends TestCase
{
    /**
     * @group slow
     * @group integration
     */
    public function testSlowOperation(): void
    {
        // ...
    }
}
# Nur bestimmte Gruppen
./vendor/bin/phpunit --group slow

# Gruppen ausschließen
./vendor/bin/phpunit --exclude-group slow

Best Practices

💡 Empfehlungen:
  • Ein Konzept pro Test (Single Assertion Rule)
  • Sprechende Testnamen: testUserCannotLoginWithWrongPassword
  • Arrange-Act-Assert Pattern
  • Tests unabhängig voneinander
  • Keine Produktionsdatenbank in Tests
  • Tests bei jedem Commit ausführen (CI/CD)

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120