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

Fixtures für Testdaten

Fixtures für Testdaten

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

Zum Abschluss von Block 4 lösen wir ein praktisches Problem: statt bei JEDEM Datenbank-Reset manuell Testdaten über die Web-Oberfläche einzugeben, generieren wir sie REPRODUZIERBAR per Code.

Das Fixtures-Bundle installieren

composer require --dev doctrine/doctrine-fixtures-bundle

Eine Fixture-Klasse erstellen

php bin/console make:fixtures ProjectFixtures
src/DataFixtures/ProjectFixtures.php
<?php

declare(strict_types=1);

namespace App\DataFixtures;

use App\Entity\Project;
use App\Entity\Task;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;

class ProjectFixtures extends Fixture
{
    public function load(ObjectManager $manager): void
    {
        $projekt = (new Project())
            ->setName('Website-Relaunch')
            ->setDescription('Kompletter Redesign der Firmenwebsite');

        $manager->persist($projekt);

        $aufgabenTitel = ['Design-Konzept erstellen', 'Backend aufsetzen', 'Texte finalisieren'];
        foreach ($aufgabenTitel as $titel) {
            $aufgabe = (new Task())
                ->setTitel($titel)
                ->setProject($projekt);

            $manager->persist($aufgabe);
        }

        $manager->flush();
    }
}

Beachten Sie: flush() wird nur EINMAL am ENDE aufgerufen, NICHT nach jedem persist() – bei größeren Fixture-Mengen deutlich performanter, da alle Objekte in EINER Transaktion geschrieben werden.

Fixtures laden

php bin/console doctrine:fixtures:load

Achtung: doctrine:fixtures:load LEERT standardmäßig ALLE Tabellen, BEVOR es die Fixtures lädt – KEIN additiver Vorgang! NIEMALS versehentlich gegen eine Produktionsdatenbank ausführen. Mit --append lassen sich Fixtures OHNE vorheriges Leeren hinzufügen, falls das gewünscht ist.

Beziehungen zwischen mehreren Fixture-Klassen

Braucht eine Fixture-Klasse Objekte aus einer ANDEREN – z. B. Aufgaben, die einem bestimmten Nutzer zugewiesen sind – nutzt man ObjectReferences statt die Fixtures manuell in der richtigen Reihenfolge auszuführen:

src/DataFixtures/UserFixtures.php
<?php

declare(strict_types=1);

namespace App\DataFixtures;

use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;

class UserFixtures extends Fixture
{
    public const string ANNA_REFERENCE = 'user-anna';

    public function load(ObjectManager $manager): void
    {
        $anna = (new User())->setName('Anna Schmidt');
        $manager->persist($anna);
        $manager->flush();

        $this->addReference(self::ANNA_REFERENCE, $anna);
    }
}
src/DataFixtures/ProjectFixtures.php
use App\DataFixtures\UserFixtures;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;

class ProjectFixtures extends Fixture implements DependentFixtureInterface
{
    public function load(ObjectManager $manager): void
    {
        $projekt = (new Project())->setName('Website-Relaunch');

        $aufgabe = (new Task())
            ->setTitel('Design-Konzept erstellen')
            ->setProject($projekt);

        // Referenz aus UserFixtures wiederverwenden:
        $anna = $this->getReference(UserFixtures::ANNA_REFERENCE, User::class);
        $projekt->addMitglied($anna);

        $manager->persist($projekt);
        $manager->persist($aufgabe);
        $manager->flush();
    }

    public function getDependencies(): array
    {
        return [UserFixtures::class];
    }
}

DependentFixtureInterface/getDependencies() stellt sicher, dass UserFixtures IMMER VOR ProjectFixtures ausgeführt wird – unabhängig von der alphabetischen oder zufälligen Standard-Reihenfolge.

Faker: realistischere Testdaten generieren

composer require --dev fakerphp/faker
use Faker\Factory;

$faker = Factory::create('de_DE');

for ($i = 0; $i < 20; $i++) {
    $aufgabe = (new Task())
        ->setTitel($faker->sentence(4))
        ->setProject($projekt);

    $manager->persist($aufgabe);
}

Tipp: Faker eignet sich hervorragend für GROSSE Mengen realistisch aussehender Testdaten (z. B. für Performance-Tests in Block 8), aber für die KERN-Fixtures (wie Anna in diesem Kapitel) sind feste, benannte Werte besser – so bleibt in Tests (Block 7) NACHVOLLZIEHBAR, WELCHER konkrete Nutzer gemeint ist.

Damit ist Block 4 (Doctrine ORM & Datenbank) abgeschlossen! Unser Aufgaben-Manager hat jetzt eine vollständige, migrationsversionierte Datenbankstruktur mit reproduzierbaren Testdaten. Block 5 fügt Security hinzu – Registrierung, Login und Zugriffskontrolle, damit nur Projekt-Mitglieder ihre eigenen Projekte sehen.