Laravel Testing 2026: Pest, Mocking und technische Interviewfragen
Ein umfassender Leitfaden zu Laravel Testing mit Pest 4: Unit Tests, Feature Tests, Mocking-Strategien, Architektur-Tests und haeufige Interviewfragen.

Die Testlandschaft in Laravel hat sich mit Pest 4, Mutation Testing und Architektur-Presets grundlegend veraendert. Laravel 12 wird mit erstklassiger Pest-Unterstuetzung ausgeliefert, wodurch das Testen deutlich ausdruecklicher und weniger umstaendlich als mit reinem PHPUnit ausfaellt. Dieser Leitfaden behandelt die Muster, die sowohl fuer Produktionsanwendungen als auch fuer technische Vorstellungsgespraeche relevant sind.
Pest 4.7 (basierend auf PHPUnit 12) ist das Standard-Testing-Framework fuer Laravel 12. Es erfordert PHP 8.3+ und bringt Mutation Testing, zeitbalanciertes Sharding und Architektur-Presets von Haus aus mit.
Pest 4 in einem Laravel 12 Projekt einrichten
Jede neue Laravel 12 Anwendung wird automatisch mit Pest aufgesetzt. Fuer bestehende Projekte dauert die Migration von PHPUnit oder Pest 3 nur wenige Minuten. Die Konfiguration befindet sich in tests/Pest.php, wo globale Traits und Hilfsmethoden registriert werden.
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()
->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Feature');Diese einzelne Datei ersetzt den alten CreatesApplication Trait und die Vererbung der Basis-Testklasse. Der RefreshDatabase Trait kapselt jeden Test in eine Datenbanktransaktion, die Aenderungen automatisch zurueckrollt.
use App\Models\User;
it('registers a new user with valid data', function () {
= ->postJson('/api/register', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'password' => 'SecurePass123!',
'password_confirmation' => 'SecurePass123!',
]);
->assertStatus(201)
->assertJsonStructure(['user' => ['id', 'name', 'email']]);
expect(User::where('email', 'jane@example.com')->exists())->toBeTrue();
});Pests expect() API harmoniert nahtlos mit PHPUnit-Assertions. Der assertJsonStructure Aufruf validiert die Antwortstruktur, waehrend expect()->toBeTrue() den Datenbankzustand bestaetigt. Beide Stile koexistieren ohne Konflikte.
Unit Tests vs Feature Tests in Laravel
Die Unterscheidung zwischen Unit- und Feature-Tests in Laravel bestimmt, welche Teile des Frameworks gestartet werden. Unit Tests laufen ohne den Application Container, was sie schneller macht, aber auf reine Logik beschraenkt. Feature Tests starten die vollstaendige Anwendung und ermoeglichen HTTP-Aufrufe, Datenbankabfragen und Service-Aufloesungen.
use App\Services\PriceCalculator;
describe('PriceCalculator', function () {
it('applies a percentage discount correctly', function () {
= new PriceCalculator();
// 20% off a 150.00 base price
= ->applyDiscount(150.00, 20);
expect()->toBe(120.00);
});
it('rejects negative discount values', function () {
= new PriceCalculator();
expect(fn () => ->applyDiscount(100.00, -5))
->toThrow(InvalidArgumentException::class);
});
});Unit Tests zielen auf isolierte Klassen ohne externe Abhaengigkeiten ab. Der describe Block gruppiert zusammengehoerige Assertions, und Pest 4 unterstuetzt verschachtelte describe Bloecke fuer komplexe Testhierarchien.
Feature Tests sollten den Grossteil einer Laravel Test Suite ausmachen. Sie erkennen Integrationsfehler, die Unit Tests uebersehen, wie etwa fehlerhafte Route-Middleware, fehlende Validierungsregeln oder defekte Eloquent-Beziehungen. Eine gaengige Faustregel lautet: Wenn der Code die Datenbank, die HTTP-Schicht oder eine Facade beruehrt, gehoert ein Feature Test dazu.
Mocking-Strategien mit Facades und Mockery
Mocking beim Laravel-Testing isoliert den zu testenden Code von externen Abhaengigkeiten. Laravel Facades bieten integrierte Fake-Implementierungen fuer Queues, Events, Benachrichtigungen, Mail und Storage. Mockery uebernimmt alles andere.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
use App\Mail\OrderConfirmation;
use App\Jobs\ProcessPayment;
it('dispatches payment job and sends confirmation email', function () {
// Fake both Mail and Queue facades
Mail::fake();
Queue::fake();
= User::factory()->create();
= Order::factory()->for()->create([
'total' => 99.99,
'status' => 'pending',
]);
// Act: confirm the order via HTTP
->actingAs()
->postJson("/api/orders/{->id}/confirm")
->assertOk();
// Assert: payment job was dispatched with correct amount
Queue::assertPushed(ProcessPayment::class, function () use () {
return ->order->id === ->id
&& ->order->total === 99.99;
});
// Assert: confirmation email was sent to the user
Mail::assertSent(OrderConfirmation::class, function () use () {
return ->hasTo(->email);
});
});Facade Fakes fangen Aufrufe auf Framework-Ebene ab und verhindern, dass tatsaechlich E-Mails versendet oder Jobs in die Warteschlange gestellt werden. Die Closure-basierten Assertions ueberpruefen die exakten Daten, die an jede Komponente uebergeben werden.
Interne Domain-Klassen sollten nicht gemockt werden. Das Mocking gehoert an die Systemgrenzen: Drittanbieter-APIs, Mail, Queues, Dateisysteme. Uebertriebenes Mocking macht Tests fragil und koppelt sie zu eng an Implementierungsdetails.
Fuer Abhaengigkeiten, die keine Facades sind, erfolgt die Injektion ueber den Konstruktor mit Mockery:
use App\Services\PaymentGateway;
use App\Services\StripeClient;
it('charges the customer through the payment gateway', function () {
// Create a mock of the Stripe client
= Mockery::mock(StripeClient::class);
->shouldReceive('charge')
->once()
->with('cus_abc123', 5000, 'usd')
->andReturn(['status' => 'succeeded', 'id' => 'ch_xyz']);
// Bind the mock in the container
->app->instance(StripeClient::class, );
= app(PaymentGateway::class);
= ->processCharge('cus_abc123', 50.00);
expect(['status'])->toBe('succeeded');
});Das Binden des Mocks mit ->app->instance() ersetzt die echte Implementierung fuer die Dauer des Tests. Mockery verifiziert, dass charge genau einmal mit den erwarteten Argumenten aufgerufen wurde.
Architektur-Tests mit Pest Presets
Pest 4 enthaelt Architektur-Tests, die strukturelle Regeln im gesamten Codebase durchsetzen. Diese Tests laufen gegen den AST, nicht gegen die Laufzeit, was sie extrem schnell macht.
arch('controllers do not use Eloquent directly')
->expect('App\Http\Controllers')
->not->toUse('Illuminate\Database\Eloquent');
arch('services are final classes')
->expect('App\Services')
->toBeFinal();
arch('no debugging functions in production code')
->expect(['dd', 'dump', 'var_dump', 'ray'])
->not->toBeUsed();Die erste Regel verhindert, dass Controller direkt auf die Datenbank zugreifen, und erzwingt damit ein Service-Layer-Pattern. Die zweite stellt sicher, dass Services nicht erweitert werden koennen, was die Vererbungskomplexitaet reduziert. Die dritte faengt uebrig gebliebene Debug-Anweisungen ab, bevor sie in die Produktion gelangen.
Laravel-spezifische Presets stehen ebenfalls zur Verfuegung:
arch()->preset()->laravel();
arch()->preset()->security();
arch()->preset()->php();Diese drei Zeilen setzen Dutzende von Regeln durch: Models muessen die korrekte Basisklasse erweitern, Controller duerfen keine Geschaeftslogik enthalten, unsichere Funktionen wie eval() oder md5() zum Hashing sind verboten, und Standard-PHP-Konventionen werden eingehalten.
Bereit für deine Laravel-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Mutation Testing zur Ueberpruefung der Testqualitaet
Code Coverage misst, welche Zeilen waehrend der Tests ausgefuehrt werden. Mutation Testing geht weiter: Es veraendert den Quellcode und prueft, ob die Tests die Aenderung erkennen. Wenn eine Mutation ueberlebt, hat die Test Suite eine Luecke.
# Run mutation testing on a specific class
php artisan test --mutate --class=App\\Services\\PriceCalculatorPest 4 fuehrt Mutationen ein wie das Aendern von > zu >=, das Entfernen von return-Anweisungen und das Umkehren von booleschen Bedingungen. Ein Mutation Score unter 80% deutet in der Regel darauf hin, dass Tests zwar Ausgaben verifizieren, aber Randfaelle nicht abpruefen.
// Example: this test has high coverage but low mutation score
it('calculates shipping cost', function () {
= calculateShipping(weight: 5.0, zone: 'domestic');
// Only checks that the result is numeric
expect()->toBeFloat();
});
// Improved: catches mutations by asserting the exact value
it('calculates domestic shipping for 5kg package', function () {
= calculateShipping(weight: 5.0, zone: 'domestic');
// Exact assertion catches operator and value mutations
expect()->toBe(12.50);
});Der erste Test besteht selbst dann, wenn die Berechnungslogik voellig falsch ist, solange ein Float zurueckgegeben wird. Der zweite Test schlaegt sofort fehl, wenn eine Mutation die Formel veraendert. Spezifische Assertions fuehren zu hoeheren Mutation Scores.
Datenbank-Testing-Patterns und Factories
Laravel Model Factories generieren realistische Testdaten ohne manuellen Array-Aufbau. Pest 4 in Kombination mit Factories erzeugt lesbaren, wartbaren Datenaufbau.
use App\Models\Article;
use App\Models\User;
it('publishes a draft article and updates the timestamp', function () {
= User::factory()->create(['role' => 'editor']);
= Article::factory()
->for(, 'author')
->draft()
->create(['title' => 'Testing Best Practices']);
->actingAs()
->patchJson("/api/articles/{->id}/publish")
->assertOk()
->assertJsonPath('data.status', 'published');
->refresh();
expect(->status)->toBe('published')
->and(->published_at)->not->toBeNull()
->and(->published_at->isToday())->toBeTrue();
});Der draft() Factory State setzt Standardwerte fuer unveroeffentlichte Artikel. Verkettete expect() Assertions mit ->and() lesen sich wie natuerliche Sprache und liefern bei Fehlern aussagekraeftige Meldungen.
Mit php artisan test --parallel werden Tests ueber mehrere Prozesse verteilt. Laravel erstellt automatisch separate Testdatenbanken fuer jeden Prozess, um Datenkonflikte zu vermeiden. In Kombination mit Pest 4s zeitbalanciertem Sharding ergibt sich eine optimale CI-Performance.
Haeufige Laravel Testing Interviewfragen
Technische Vorstellungsgespraeche fuer Laravel-Positionen prufen haeufig das Testing-Wissen ab. Die folgenden Fragen tauchen am haeufigsten auf, zusammen mit dem, was eine starke Antwort abdecken sollte.
Was ist der Unterschied zwischen fake(), mock() und spy() beim Laravel-Testing?
Facade fake() ersetzt die gesamte Facade durch eine In-Memory-Implementierung (Mail::fake, Queue::fake). mock() ueber Mockery setzt Erwartungen vor der Ausfuehrung und schlaegt fehl, wenn diese nicht erfuellt werden. spy() zeichnet Interaktionen auf und erlaubt Assertions nach der Ausfuehrung, ohne vorab Erwartungen festzulegen. Die Wahl haengt davon ab, ob der Test Verhalten verifizieren (mock), Interaktionen aufzeichnen (spy) oder Seiteneffekte verhindern (fake) soll.
Wie unterscheidet sich RefreshDatabase von DatabaseTransactions?
RefreshDatabase fuehrt Migrationen einmal aus und kapselt jeden Test in eine Transaktion. DatabaseTransactions geht davon aus, dass die Datenbank bereits das korrekte Schema hat, und kapselt die Tests nur in Transaktionen. RefreshDatabase ist sicherer fuer CI-Pipelines, in denen die Datenbank moeglicherweise noch nicht existiert. DatabaseTransactions ist schneller, wenn das Schema garantiert aktuell ist.
Wann sollten Feature Tests gegenueber Unit Tests bevorzugt werden?
Feature Tests sollten jeden Code abdecken, der mit der HTTP-Schicht, der Datenbank oder Laravel-Services interagiert. Unit Tests sind fuer reine Funktionen und Value Objects ohne Framework-Abhaengigkeiten reserviert. In einer typischen Laravel-Anwendung ueberwiegen Feature Tests gegenueber Unit Tests im Verhaeltnis von etwa 3:1 oder hoeher. Dies spiegelt die Realitaet wider, dass der Grossteil des Laravel-Codes inherent mit dem Framework integriert ist.
Wie verbessert Mutation Testing die Testqualitaet ueber Code Coverage hinaus?
Code Coverage misst Ausfuehrungspfade. Ein Test kann 100% Coverage erreichen, indem er jede Methode aufruft, ohne etwas Aussagekraeftiges zu pruefen. Mutation Testing veraendert den Quellcode (aendert Operatoren, entfernt Returns, kehrt Booleans um) und verifiziert, dass mindestens ein Test fehlschlaegt. Ueberlebende Mutationen zeigen Assertions auf, die zu locker oder gaenzlich fehlend sind. php artisan test --mutate erzeugt einen Mutation Score in Prozent neben der Standard-Coverage.
Fuer weitere Laravel Interviewfragen deckt die SharpSkill-Fragendatenbank Authentifizierung, Service Container Patterns, Eloquent-Beziehungen und Queue-Architektur ab.
HTTP-Response-Tests und JSON-Assertions
Laravels HTTP-Testing-Helper verifizieren Statuscodes, Header, JSON-Strukturen und Redirect-Ziele. In Kombination mit Pest entstehen kompakte Integrationstests.
use App\Models\User;
describe('API Authentication', function () {
it('rejects unauthenticated requests with 401', function () {
->getJson('/api/profile')
->assertUnauthorized();
});
it('returns the authenticated user profile', function () {
= User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
->actingAs()
->getJson('/api/profile')
->assertOk()
->assertJson([
'data' => [
'name' => 'John Doe',
'email' => 'john@example.com',
],
]);
});
it('validates required fields on registration', function () {
->postJson('/api/register', [])
->assertUnprocessable()
->assertJsonValidationErrors(['name', 'email', 'password']);
});
});Der describe Block gruppiert authentifizierungsbezogene Tests. Jeder Testname beschreibt das erwartete Verhalten, nicht die Implementierung. Die Methode assertJsonValidationErrors prueft, ob bestimmte Felder Validierungsfehlermeldungen enthalten.
Fazit
- Pest 4 mit Laravel 12 eliminiert Boilerplate durch eine fluessige Konfigurations-API,
expect()Verkettungen und automatische Testerkennung - Feature Tests sollten den Kern einer Laravel Test Suite bilden, waehrend Unit Tests fuer isolierte Geschaeftslogik reserviert bleiben
- Facade Fakes (
Mail::fake(),Queue::fake()) uebernehmen das Mocking auf Framework-Ebene, waehrend Mockery Drittanbieter-Abhaengigkeiten handhabt, die ueber den Container injiziert werden - Architektur-Tests setzen strukturelle Regeln durch (kein Eloquent in Controllern, keine Debug-Funktionen) ohne Laufzeit-Overhead
- Mutation Testing mit
--mutateerkennt schwache Assertions, die Code Coverage allein uebersieht - Factory States und verkettete
expect()->and()Assertions halten den Testdatenaufbau lesbar und die Assertions spezifisch - Fuer die Laravel-Interviewvorbereitung demonstriert das Verstaendnis der Mock/Fake/Spy-Unterscheidung, des
RefreshDatabase-Verhaltens und des Mutation Testings eine Testing-Reife jenseits einfacher Coverage
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Laravel 12 im Jahr 2026: Neue Features, Starter Kits und Interview-Fragen
Laravel 12 bringt komplett überarbeitete Starter Kits mit React 19, Vue 3, Livewire 4 und WorkOS AuthKit. Ein umfassender Leitfaden zu neuen Features, dem Upgrade-Pfad und wichtigen Interview-Fragen für 2026.

Laravel und PHP Interviewfragen: Die Top 25 in 2026
Die 25 haeufigsten Laravel- und PHP-Interviewfragen. Eloquent ORM, Middleware, Artisan, Queues, Tests und Architektur mit ausfuehrlichen Antworten und Codebeispielen.

Laravel Middleware im Detail: Authentifizierung, Rate Limiting und eigene Middleware
Umfassender Leitfaden zu Laravel Middleware mit praktischen Beispielen zu Authentifizierung, Rate Limiting, eigener Middleware-Erstellung und fortgeschrittenen Produktionsmustern.