Symfony-Tests mit Zenstruck Foundry auf das nächste Level bringen

· Silas Joisten · 3 Minuten zum Lesen
Toy factory production line

Zenstruck Foundry hat die Art und Weise, wie wir Tests in Symfony schreiben, revolutioniert. In diesem Beitrag erfährst du, wie uns ausdrucksstarke Factories, isolierte Testdaten und ein reibungsloseres Entwicklererlebnis dabei geholfen haben, unseren Test-Workflow zu optimieren und die Produktivität zu steigern.

Zenstruck Foundry ist eine leistungsstarke Bibliothek, die die Erstellung von Testdaten in Symfony-Anwendungen deutlich vereinfacht. Im Kern bietet Foundry ausdrucksstarke, automatisch vervollständigte Factories für Doctrine-Entitäten, mit denen Entwickler Daten schnell und ohne viel Boilerplate erzeugen können.

Dank der Integration mit Faker, Unterstützung für Doctrine ORM/ODM und Features wie „Stories“ steigert Foundry die Produktivität der Entwickler und erhöht die Zuverlässigkeit von Tests erheblich.

Eine Factory für eine Doctrine-Entität erstellen

Stellen wir uns vor, wir haben eine User Entity:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string')]
    private string $email;

    #[ORM\Column(type: 'string')]
    private string $name;
}

Wir können jetzt eine Factory dafür generieren:

bin/console make:factory App\\Entity\\User

Dieser Befehl erstellt die folgende UserFactory Klasse:

// src/Factory/UserFactory.php
namespace App\Factory;

use App\Entity\User;
use Zenstruck\Foundry\Persistence\PersistentObjectFactory;
use Zenstruck\Foundry\Proxy;

/**
 * @extends PersistentObjectFactory<User>
 */
final class UserFactory extends PersistentObjectFactory
{
    protected function defaults(): array
    {
        return [
            'email' => self::faker()->email(),
            'name' => self::faker()->name(),
        ];
    }

    protected static function class(): string
    {
        return User::class;
    }
}

Verwendung von Factories in Tests

Mit der erstellten Factory kannst du nun Benutzer in deinen Testfällen erzeugen:

public function testGetEmail(): void
{
    $user = UserFactory::createOne([
        'email' => $expected = 'john@doe.com'
    ]);

    self::assertSame($expected, $user->getEmail());
}

Du brauchst mehr Benutzer?

$users = UserFactory::createMany(5);

Einführung in Stories

Stories sind eine hervorragende Möglichkeit, wiederverwendbare Datenszenarien zu definieren. Wenn du z. B. möchtest, dass ein Standard-Admin-Benutzer immer existiert, kannst du ihn in einer Story definieren:

// src/Story/DefaultUsersStory.php
namespace App\Story;

use App\Factory\UserFactory;
use Zenstruck\Foundry\Story;

final class DefaultUsersStory extends Story
{
    public function build(): void
    {
        UserFactory::createOne([
            'email' => 'admin@example.com',
            'name' => 'Administrator',
        ]);
    }
}

Diese Story kannst du über Doctrine Fixtures laden:

bin/console doctrine:fixtures:load

Achte darauf, dass der Foundry Loader in der FoundryBundle-Konfiguration registriert ist, falls erforderlich.

Eingebaute Factories

Foundry bringt auch spezialisierte Factories für fortgeschrittene Anwendungsfälle mit:

  • ArrayFactory: Zum Erzeugen von Arrays, z. B. zur Simulation von API-Antworten.

  • ObjectFactory: Zum Erzeugen von Objekten, ohne sie zu persistieren.

  • PersistentProxyObjectFactory: Hilfreich, wenn erstellte Objekte direkt in der Datenbank gespeichert und als Proxy verwendet werden sollen.

Testing von Value Objects und Aggregates in DDD

Ein besonderes Highlight von Zenstruck Foundry ist die nahtlose Unterstützung komplexer Domänenmodelle, insbesondere Value Objects und Aggregates im Sinne des Domain-Driven Design (DDD). Foundry vereinfacht die Erstellung solcher Entitäten und ihrer zugehörigen Value Objects – ideal für das Testen anspruchsvoller Architekturen.

Mehr zu den Grundlagen von Domain-Driven Design kannst du hier nachlesen.

Ein Beispiel: Du möchtest ein Value Object wie Price testen. Mit einer passenden Factory kannst du realistische Daten generieren und in deine Tests einfließen lassen:

final readonly class Price
{
    public function __construct(
        public int $amount,
        public string $currency,
    ) {
    }
}
use Zenstruck\Foundry\Object\Instantiator\ObjectFactory;

final class PriceFactory extends ObjectFactory
{
    protected function defaults(): array
    {
        return [
            'amount' => self::faker()->numberBetween(100, 1000),
            'currency' => self::faker()->randomElement(['€', '$']),
        ];
    }

    protected static function getClass(): string
    {
        return Price::class;
    }
}

So kannst du das Verhalten von Aggregates testen, ohne dich um die komplexe Erstellung oder Verwaltung der Daten kümmern zu müssen. Foundry hilft dir, realistische Domänenmodelle zu simulieren und sicherzustellen, dass die Interaktionen zwischen Aggregates und Value Objects realitätsnah funktionieren.

Fazit

Zenstruck Foundry ist ein unverzichtbares Werkzeug in unserem Symfony-Werkzeugkasten geworden. Es reduziert Boilerplate-Code, verbessert die Testzuverlässigkeit und erhöht die Produktivität. Die Möglichkeit, Stories für wiederverwendbare Szenarien zu nutzen und fortgeschrittene Factories für komplexe Anforderungen bereitzustellen, macht Foundry zu einem Must-Have für jedes Symfony-Projekt.

Darüber hinaus passt sich Foundry hervorragend an die Prinzipien des Domain-Driven Design an – ideal also für Tests komplexer Domänenmodelle mit Aggregates und Value Objects.

Starte mit Foundry

Verwandle deinen Symfony-Testworkflow mit Foundry. Generiere schnell Testdaten, automatisiere wiederholte Aufgaben und sorge für zuverlässigere Tests.

Das könnte dich auch interessieren

Fabien Potencier
Elise Hamimi

SymfonyCon Amsterdam 2025: Unser Rückblick und die Highlights

Nach einer legendären ersten Ausgabe im Jahr 2019 feierte die SymfonyCon ihr großes Comeback in Amsterdam. Von Anfang an war die Energie einer mit Spannung erwarteten Konferenz zu spüren: mehr als 1.200 Teilnehmer, 39 Nationalitäten, das größte Treffen der Symfony-Community des Jahres, großartige Entdeckungen ... und eine ausgelassene Atmosphäre. Dieses Jahr war etwas ganz Besonderes, denn es war das 20-jährige Jubiläum von Symfony. SensioLabs war dabei: Wir berichten Ihnen ausführlich über unsere Erfahrungen dort!

Mehr erfahren
PHP 8.5 URI extension
Oskar Stark

PHP 8.5's neue URI-Erweiterung: Ein Game-Changer für URL-Parsing

PHP 8.5 führt eine leistungsstarke neue URI-Erweiterung ein, die die URL-Verarbeitung modernisiert. Mit Unterstützung für RFC 3986 und WHATWG-Standards bietet die neue Uri-Klasse unveränderliche Objekte, fluent Interfaces und korrekte Validierung - und behebt alle Einschränkungen der veralteten parse_url()-Funktion. Dieser Leitfaden zeigt praktische Vorher/Nachher-Beispiele und erklärt, wann welcher Standard zu verwenden ist.

Mehr erfahren
Two images: on the left many cars stuck in a traffic jam with the sign "All directions" above, on the right a blue car moving forward alone on the highway with the sign "Service Subscriber" and a Symfony logo above
Steven Renaux

Symfony Lazy Services mit Stil – Steigere deine Entwicklererfahrung mit Service Subscribers

Steigere die Performance und Developer Experience (DX) deiner Symfony-App! Erfahre, wie du Service Subscribers und Traits für das verzögerte Laden von Services verwendest, um die sofortige Instanziierung zu reduzieren, Abhängigkeiten zu vereinfachen und modularen, wartbaren Code zu schreiben.

Mehr erfahren
the surface of the earth seen from the space with city lights forming networks
Imen Ezzine

HTTP-Verben: Der ultimative Leitfaden

Hier erklären wir dir die Grundlagen von GET, POST, PUT, DELETE und mehr. In diesem Artikel erfährst du alles über die Funktionsweise, die Anwendungsmöglichkeiten und die Sicherheitsauswirkungen.

Mehr erfahren
Domain Driven Design practical approach
Silas Joisten

Anwendung von Domain-Driven Design in PHP und Symfony: Ein praktischer Leitfaden

Erfahre anhand praktischer Beispiele, wie du die Prinzipien des Domain-Driven Design (DDD) in Symfony anwendest. Entdecke die Leistungsfähigkeit von Value Objects, Repositories und Bounded Contexts.

Mehr erfahren
type-safety-uuid
Oskar Stark

Typensichere IDs mit Symfony und Doctrine: Verwendung dedizierter ID-Klassen

Lerne, wie du die Typensicherheit in Symfony und Doctrine durch die Verwendung dedizierter ID-Klassen wie BookId und UserId anstelle roher UUIDs verbessern kannst. Dieser Ansatz verhindert die Verwechslung von IDs, verbessert die Codeklarheit und sorgt für eine bessere Integration mit Symfony Messenger und Repository-Methoden. Entdecke praxisnahe Beispiele und Best Practices zur Implementierung typsicherer IDs in deinen Symfony-Anwendungen.

Mehr erfahren
Grey Cargo Plane with a Blue Sky
Rémi Brière

Agilität und der Cargo-Kult - Teil 1

Agilität ist mehr als nur Rituale und Tools. In diesem ersten Artikel unserer Scrum-Serie untersuchen wir das Phänomen des Cargo-Kults und wie blinde Nachahmung eine echte agile Transformation behindern kann.

Mehr erfahren
Semantic Versus Calendar Versioning
Silas Joisten

SemVer vs. CalVer: Welche Versionierungsstrategie ist die richtige für dich?

SemVer sorgt für Stabilität in Bibliotheken, während CalVer Projekte an Veröffentlichungszyklen anpasst. Erfahre die wichtigsten Unterschiede und besten Anwendungsfälle, um deine Versionierungsstrategie zu optimieren.

Mehr erfahren
Image