> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Mocks

> Wie Sie mit den Mock- und Test-Double-Funktionen von Laravel Ihre Tests unabhängig ausführen.

## Wozu Mocks

Beim Schreiben von Tests gibt es Vorgänge, die Sie nicht tatsächlich ausführen möchten – etwa den Versand von E-Mails, das Lesen und Schreiben von Caches oder Aufrufe an externe APIs.
Solche Vorgänge durch eine „Fälschung, die sich wie das Original verhält“ zu ersetzen, nennt man Mocking.

Die Vorteile von Mocks:

* **Schnelle Tests** – Es werden keine externen Dienste oder aufwendigen Operationen ausgeführt, daher laufen die Tests schnell ab.
* **Stabile Tests** – Die Tests hängen nicht vom Zustand externer Dienste ab und liefern stets dasselbe Ergebnis.
* **Klarer Testfokus** – Es lässt sich gezielt eine einzelne Klasse oder Methode prüfen.

Laravel bietet direkt einsetzbare Helfer für das Mocken von Events, Jobs, Fassaden usw.
Intern verwendet es [Mockery](https://github.com/mockery/mockery), sodass Sie ohne komplexes Setup loslegen können.

```mermaid theme={null}
graph LR
    A["Test"] --> B["Mock<br>(Fälschung)"]
    A --> C["Produktivcode"]
    B --> D["wird nicht ausgeführt<br>(externe API, E-Mail etc.)"]
    C --> B
    style B fill:#f9a,stroke:#c66
    style D fill:#eee,stroke:#aaa
```

## Mock-Objekte

Um ein Objekt zu mocken, das über den Service-Container injiziert wird, binden Sie die Mock-Instanz in den Container ein.
Der Container verwendet dann statt einer neu erzeugten Instanz Ihre Mock-Instanz.

<CodeGroup>
  ```php Pest theme={null}
  use App\Service;
  use Mockery;
  use Mockery\MockInterface;

  test('something can be mocked', function () {
      $this->instance(
          Service::class,
          Mockery::mock(Service::class, function (MockInterface $mock) {
              $mock->expects('process');
          })
      );
  });
  ```

  ```php PHPUnit theme={null}
  use App\Service;
  use Mockery;
  use Mockery\MockInterface;

  public function test_something_can_be_mocked(): void
  {
      $this->instance(
          Service::class,
          Mockery::mock(Service::class, function (MockInterface $mock) {
              $mock->expects('process');
          })
      );
  }
  ```
</CodeGroup>

### Die Methode `mock()`

Mit der Methode `mock()`, die die TestCase-Basisklasse von Laravel bereitstellt, schreiben Sie dasselbe kürzer.

```php theme={null}
use App\Service;
use Mockery\MockInterface;

$mock = $this->mock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});
```

### Die Methode `partialMock()`

Wenn Sie nur einen Teil der Methoden eines Objekts mocken möchten, verwenden Sie `partialMock()`.
Nicht gemockte Methoden werden wie üblich ausgeführt.

```php theme={null}
use App\Service;
use Mockery\MockInterface;

$mock = $this->partialMock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});
```

### Die Methode `spy()`

Ein Spy ist einem Mock ähnlich, unterscheidet sich aber darin, dass die Interaktion nach der Codeausführung überprüft wird.
Während ein Mock vorab festlegt „diese Methode wird aufgerufen werden“, prüft ein Spy im Nachhinein „wurde diese Methode aufgerufen“.

```php theme={null}
use App\Service;

$spy = $this->spy(Service::class);

// ...den zu testenden Code ausführen...

$spy->shouldHaveReceived('process');
```

```mermaid theme={null}
graph TD
    subgraph "Mock"
        M1["Vorab Erwartung setzen<br>expects('process')"] --> M2["Code ausführen"] --> M3["Automatische Prüfung"]
    end
    subgraph "Spy"
        S1["Spy einrichten"] --> S2["Code ausführen"] --> S3["Prüfung im Nachhinein<br>shouldHaveReceived('process')"]
    end
```

## Fassaden mocken

[Fassaden](/de/facades) unterscheiden sich von gewöhnlichen statischen Methodenaufrufen dadurch, dass sie sich mocken lassen.
Sie bieten die Testbarkeit von Dependency Injection bei gleichzeitig knapper Syntax.

Als Beispiel ein Controller, der den Cache verwendet:

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * Gibt die Liste aller Benutzer der Anwendung zurück.
     */
    public function index(): array
    {
        $value = Cache::get('key');

        return [
            // ...
        ];
    }
}
```

Um die Methode `get` der `Cache`-Fassade zu mocken, verwenden Sie `expects()`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Support\Facades\Cache;

  test('get index', function () {
      Cache::expects('get')
          ->with('key')
          ->andReturn('value');

      $response = $this->get('/users');

      // ...
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Illuminate\Support\Facades\Cache;
  use Tests\TestCase;

  class UserControllerTest extends TestCase
  {
      public function test_get_index(): void
      {
          Cache::expects('get')
              ->with('key')
              ->andReturn('value');

          $response = $this->get('/users');

          // ...
      }
  }
  ```
</CodeGroup>

<Warning>
  Mocken Sie nicht die `Request`-Fassade. Übergeben Sie stattdessen Eingabewerte an HTTP-Testmethoden wie `get` oder `post`. Rufen Sie ebenso statt die `Config`-Fassade zu mocken in Ihrem Test `Config::set()` auf.
</Warning>

## Fassaden als Spy

Um eine Fassade als Spy zu beobachten, rufen Sie die Methode `spy()` der entsprechenden Fassade auf.
Ein Spy ist praktisch, wenn Sie Interaktionen nach der Codeausführung überprüfen möchten.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Support\Facades\Cache;

  test('values are stored in cache', function () {
      Cache::spy();

      $response = $this->get('/');

      $response->assertStatus(200);

      Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
  });
  ```

  ```php PHPUnit theme={null}
  use Illuminate\Support\Facades\Cache;

  public function test_values_are_stored_in_cache(): void
  {
      Cache::spy();

      $response = $this->get('/');

      $response->assertStatus(200);

      Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
  }
  ```
</CodeGroup>

## Zeit manipulieren

Um zeitabhängige Logik in Tests zu prüfen, ist es praktisch, den Zeitpunkt zu ändern, den `now()` oder `Carbon::now()` zurückgeben.
Die Basisklasse für Feature-Tests von Laravel bietet dafür Helfer.

### `travel()` – Zeit verschieben

<CodeGroup>
  ```php Pest theme={null}
  test('time can be manipulated', function () {
      // In die Zukunft
      $this->travel(5)->milliseconds();
      $this->travel(5)->seconds();
      $this->travel(5)->minutes();
      $this->travel(5)->hours();
      $this->travel(5)->days();
      $this->travel(5)->weeks();
      $this->travel(5)->years();

      // In die Vergangenheit
      $this->travel(-5)->hours();

      // Zu einem bestimmten Zeitpunkt springen
      $this->travelTo(now()->subHours(6));

      // Zur aktuellen Zeit zurückkehren
      $this->travelBack();
  });
  ```

  ```php PHPUnit theme={null}
  public function test_time_can_be_manipulated(): void
  {
      // In die Zukunft
      $this->travel(5)->milliseconds();
      $this->travel(5)->seconds();
      $this->travel(5)->minutes();
      $this->travel(5)->hours();
      $this->travel(5)->days();
      $this->travel(5)->weeks();
      $this->travel(5)->years();

      // In die Vergangenheit
      $this->travel(-5)->hours();

      // Zu einem bestimmten Zeitpunkt springen
      $this->travelTo(now()->subHours(6));

      // Zur aktuellen Zeit zurückkehren
      $this->travelBack();
  }
  ```
</CodeGroup>

### Zeitmanipulation mit Closure

Wenn Sie den Reise-Methoden eine Closure übergeben, wird die Zeit für den angegebenen Zeitpunkt angehalten, die Closure ausgeführt und danach wieder zur ursprünglichen Zeit zurückgesprungen.

```php theme={null}
$this->travel(5)->days(function () {
    // Test im Zustand nach 5 Tagen
});

$this->travelTo(now()->subDays(10), function () {
    // Test zu einem bestimmten Zeitpunkt
});
```

### `freezeTime()` – Zeit einfrieren

`freezeTime()` friert die aktuelle Zeit ein. `freezeSecond()` fixiert die Zeit am Anfang der aktuellen Sekunde.

```php theme={null}
use Illuminate\Support\Carbon;

// Zeit einfrieren, Closure ausführen und danach wieder freigeben
$this->freezeTime(function (Carbon $time) {
    // ...
});

// An den Anfang der aktuellen Sekunde einfrieren und Closure ausführen
$this->freezeSecond(function (Carbon $time) {
    // ...
});
```

### Praxisbeispiel: Sperren inaktiver Threads

Zeitmanipulation ist beispielsweise hilfreich, um Funktionen wie das Sperren von Beiträgen in einem Forum nach längerer Inaktivität zu testen.

<CodeGroup>
  ```php Pest theme={null}
  use App\Models\Thread;

  test('forum threads lock after one week of inactivity', function () {
      $thread = Thread::factory()->create();

      $this->travel(1)->week();

      expect($thread->isLockedByInactivity())->toBeTrue();
  });
  ```

  ```php PHPUnit theme={null}
  use App\Models\Thread;

  public function test_forum_threads_lock_after_one_week_of_inactivity(): void
  {
      $thread = Thread::factory()->create();

      $this->travel(1)->week();

      $this->assertTrue($thread->isLockedByInactivity());
  }
  ```
</CodeGroup>

<Info>
  Zeitmanipulationsmethoden wie `travel()` sind nur in Feature-Tests verfügbar (Klassen, die von `Tests\TestCase` erben). In der Basisklasse `TestCase` von PHPUnit können sie nicht verwendet werden.
</Info>

## Methodenübersicht

### Mocks

| Methode                                | Beschreibung                                                                   |
| -------------------------------------- | ------------------------------------------------------------------------------ |
| `$this->mock(Class::class, fn)`        | Erzeugt einen vollständigen Mock einer Klasse und registriert ihn im Container |
| `$this->partialMock(Class::class, fn)` | Mockt nur einen Teil der Methoden                                              |
| `$this->spy(Class::class)`             | Erzeugt einen Spy und registriert ihn im Container                             |
| `$this->instance(Class::class, $mock)` | Registriert eine beliebige Mock-Instanz im Container                           |
| `Facade::expects('method')`            | Mockt eine Methode einer Fassade                                               |
| `Facade::spy()`                        | Beobachtet eine Fassade als Spy                                                |
| `$spy->shouldHaveReceived('method')`   | Prüft bei einem Spy, ob eine Methode aufgerufen wurde                          |

### Zeitmanipulation

| Methode                    | Beschreibung                                                     |
| -------------------------- | ---------------------------------------------------------------- |
| `$this->travel(n)->unit()` | Verschiebt die Zeit um die angegebene Einheit                    |
| `$this->travelTo(Carbon)`  | Springt zu einem bestimmten Zeitpunkt                            |
| `$this->travelBack()`      | Kehrt zur aktuellen Zeit zurück                                  |
| `$this->freezeTime(fn)`    | Friert die Zeit ein und führt eine Closure aus                   |
| `$this->freezeSecond(fn)`  | Friert die Zeit am Sekundenanfang ein und führt eine Closure aus |


## Related topics

- [Upgrade von Laravel 9 auf 10](/de/blog/upgrade-9-to-10.md)
- [Fortgeschrittenes Testen mit Pest](/de/advanced/testing-pest.md)
- [Tests](/de/packages/laravel-bluesky/testing.md)
- [HTTP-Client](/de/http-client.md)
- [Einen eigenen Provider für das AI SDK erstellen](/de/advanced/ai-sdk-custom-provider.md)
