Entwickler, der außergewöhnliche CRM- und Laravel-Lösungen liefert

Als erfahrener Entwickler spezialisiere ich mich auf Laravel- und Vue.js-Entwicklung, die Implementierung von Vtiger CRM sowie auf vielfältige WordPress-Projekte. Meine Arbeit zeichnet sich durch kreative, dynamische und benutzerzentrierte Weblösungen aus, die individuell an die Bedürfnisse meiner Kunden angepasst werden.

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 in PHPUnit und Laravel: So isolieren Sie Ihre Tests

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.


Was sind Mock-Objekte?

Mock-Objekte sind simulierte Versionen von Klassen, die:

  • Kontrollierte Antworten liefern (z. B. feste Werte statt API-Aufrufe).
  • Interaktionen überwachen (z. B. prüfen, ob eine Methode aufgerufen wurde).
  • Echte Implementierungen ersetzen, um Tests schneller und stabiler zu machen.

Wann braucht man Mocks?

SzenarioBeispiel
Externe APIsZahlungsgateways (Stripe), Adressvalidierung (Dadata)
Langsame ProzesseDatei-Uploads, PDF-Generierung
Unvorhersehbare ErgebnisseZufallsgeneratoren, Zeitstempel

Beispiel 1: Mock eines Zahlungs-Gateways

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(...);  
    }  
}  

Test mit Mock

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');  
    }  
}  

Beispiel 2: Partielle Mocks

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);  
}  

Best Practices für Mocks

1. Interfaces nutzen

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');  

2. JSON-Antworten simulieren

$this->mock(WeatherService::class, function ($mock) {  
    $mock->shouldReceive('getForecast')  
        ->andReturn(json_decode('{"temp": 25, "unit": "C"}'));  
});  

$this->get('/weather')->assertJson(['temp' => 25]);  

3. Aufrufhäufigkeit prüfen

$mock->shouldReceive('sendEmail')  
    ->once() // Muss genau 1x aufgerufen werden  
    ->with(\Mockery::type(User::class));  

Häufige Fehler

FehlerLösung
Vergessene Erwartungen->shouldReceive() fehlt → Mock wirft Fehler
Falsche ArgumentePrüfen Sie Parameter mit ->with(...)
Statische MethodenStatische Calls können nicht gemockt werden → Refactoring nötig

Tools & Tipps

  • Laravel HTTP-Fake: Simulieren Sie externe HTTP-Requests:
  Http::fake(['api.stripe.com/*' => Http::response(['id' => 'fake-id'], 200)]);  
  • Zeit manipulieren:
  $this->travelTo(now()->addDays(5)); // Zeit springt 5 Tage vor  
  • Datenbank-Transaktionen:
  use Illuminate\Foundation\Testing\DatabaseTransactions;  

Warum Mocks wichtig sind

  • Geschwindigkeit: Keine Wartezeit auf APIs.
  • 🛡️ Zuverlässigkeit: Tests scheitern nicht wegen Netzwerkfehlern.
  • 🔍 Präzision: Testen Sie genau den Code, den Sie kontrollieren.

👉 Beispielcode auf GitHub


Fazit

Mock-Objekte entkoppeln Ihren Code von externen Systemen und machen Tests schneller und vorhersehbarer. Nutzen Sie sie gezielt für:

  • Zahlungsprozesse
  • Third-Party-API-Integrationen
  • Ressourcenintensive Tasks

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.“