©Sergey Emelyanov 2025 | Alle Rechte vorbehalten
Mock-Objekte (oder Test-Doubles) sind ein unverzichtbares Werkzeug, um Code isoliert zu testen – ohne Abhängigkeiten zu externen Diensten, APIs oder komplexen Klassen. In diesem Artikel zeige ich, wie Sie Mocks in Laravel mit PHPUnit und Mockery einsetzen.
Mock-Objekte sind simulierte Versionen von Klassen, die:
Szenario | Beispiel |
---|---|
Externe APIs | Zahlungsgateways (Stripe), Adressvalidierung (Dadata) |
Langsame Prozesse | Datei-Uploads, PDF-Generierung |
Unvorhersehbare Ergebnisse | Zufallsgeneratoren, Zeitstempel |
Angenommen, Sie haben eine Klasse PaymentGatewayService, die Stripe-API-Aufrufe tätigt:
namespace App\Services;
class PaymentGatewayService {
public function doPayment(string $token, User $user): int {
// Stripe-API-Aufruf (kostet Geld!)
return Stripe::charge(...);
}
}
use Tests\TestCase;
use App\Services\PaymentGatewayService;
class PaymentTest extends TestCase {
public function test_payment_flow() {
// Mock erstellen
$mock = $this->mock(PaymentGatewayService::class);
// Erwartung definieren
$mock->shouldReceive('doPayment')
->with('test_token', \Mockery::type(User::class))
->andReturn(123); // Fake Payment-ID
// Test durchführen
$response = $this->post('/pay', ['token' => 'test_token']);
$response->assertRedirect('/success');
}
}
Manchmal möchten Sie nur bestimmte Methoden mocken, während der Rest original bleibt:
public function test_partial_mock() {
$partialMock = $this->partialMock(PaymentGatewayService::class, function ($mock) {
$mock->shouldReceive('doPayment')->once()->andReturn(456);
});
// Andere Methoden (z. B. logPayment()) werden normal ausgeführt
$this->app->instance(PaymentGatewayService::class, $partialMock);
}
Mocken Sie Interfaces statt konkreter Klassen, besonders bei final
-Klassen:
// Service-Provider binden
$this->app->bind(PaymentGatewayInterface::class, StripeGateway::class);
// Im Test
$this->mock(PaymentGatewayInterface::class)->shouldReceive('charge');
$this->mock(WeatherService::class, function ($mock) {
$mock->shouldReceive('getForecast')
->andReturn(json_decode('{"temp": 25, "unit": "C"}'));
});
$this->get('/weather')->assertJson(['temp' => 25]);
$mock->shouldReceive('sendEmail')
->once() // Muss genau 1x aufgerufen werden
->with(\Mockery::type(User::class));
Fehler | Lösung |
---|---|
Vergessene Erwartungen | ->shouldReceive() fehlt → Mock wirft Fehler |
Falsche Argumente | Prüfen Sie Parameter mit ->with(...) |
Statische Methoden | Statische Calls können nicht gemockt werden → Refactoring nötig |
Http::fake(['api.stripe.com/*' => Http::response(['id' => 'fake-id'], 200)]);
$this->travelTo(now()->addDays(5)); // Zeit springt 5 Tage vor
use Illuminate\Foundation\Testing\DatabaseTransactions;
Mock-Objekte entkoppeln Ihren Code von externen Systemen und machen Tests schneller und vorhersehbarer. Nutzen Sie sie gezielt für:
Weiterführend:
Haben Sie Fragen? Stellen Sie sie in den Kommentaren – ich antworte gern! 🚀
„Mock-Objekte sind wie Stuntmen – sie springen ein, wenn der echte Akteur zu riskant oder teuer wäre.“
©Sergey Emelyanov 2025 | Alle Rechte vorbehalten