
# Testen

Queuety stellt eine Klasse `QueueFake` bereit, die die echte Warteschlange durch einen In-Memory-Speicher ersetzt. Ausgeführte Jobs werden aufgezeichnet, statt in die Datenbank geschrieben zu werden. Auch `create_batch()` speichert Batch-Metadaten im Arbeitsspeicher. So kannst du das Ausführungsverhalten überprüfen, ohne Worker zu starten oder in die Datenbank zu schreiben. Bei der Ausführung über einen Handler-Namen wird der Handler weiterhin über die Registry aufgelöst. Rufe deshalb bei Handlern, die als Zeichenfolge angegeben sind, zuerst `Queuety::init()` auf. Instanzen von `Contracts\Job`, `chain()`, `create_batch()` und `batch()` funktionieren auch ohne diesen Aufruf.

## Fake einrichten

Rufe `Queuety::fake()` am Anfang deines Tests auf. Die Methode gibt eine Instanz von `QueueFake` zurück, die alle nachfolgenden Ausführungen aufzeichnet.

```php
use Queuety\Queuety;

class SendEmailTest extends \PHPUnit\Framework\TestCase {
    protected function setUp(): void {
        $this->fake = Queuety::fake();
    }

    protected function tearDown(): void {
        Queuety::reset();
    }
}
```

`Queuety::fake()` erstellt ein neues `QueueFake` und bindet es in die Fassade `Queuety` ein. `Queuety::dispatch()` und `Dispatchable::dispatch()` zeichnen übergebene Jobs auf. `Queuety::chain()` zeichnet jeden verketteten Job als normalen Push in Ausführungsreihenfolge auf. `Queuety::create_batch()` zeichnet sowohl die übergebenen Jobs als auch die von `assert_batched()` verwendeten Batch-Metadaten auf. `Queuety::batch()` zeichnet die übergebenen Jobs auf, erstellt aber keine gefälschten Batch-Metadaten.

Rufe `Queuety::reset()` in `tearDown()` auf, um den Fake zwischen Tests zurückzusetzen. Dabei wird der gesamte Zustand der Fassade gelöscht. Rufe daher `Queuety::init()` erneut auf, wenn ein späterer Test die echte Warteschlange benötigt.

## Überprüfen, ob Jobs übergeben wurden

### `assert_pushed()`

Überprüfe, ob eine bestimmte Job-Klasse mindestens einmal ausgeführt wurde.

```php
public function test_welcome_email_is_sent(): void {
    $this->fake = Queuety::fake();

    // Code under test...
    register_new_user( 'user@example.com' );

    $this->fake->assert_pushed( SendWelcomeEmailJob::class );
}
```

Übergib optional einen Callback, um nach Payload oder anderen Attributen zu filtern. Der Callback erhält das aufgezeichnete Job-Datenarray mit den Schlüsseln `handler`, `payload`, `queue` und `instance`. `instance` ist bei Jobs, die über die Fassade oder das Trait `null` ausgeführt werden, `Dispatchable`. Filtere daher nach `handler` und `payload`.

```php
$this->fake->assert_pushed( SendWelcomeEmailJob::class, function ( array $job ) {
    return $job['payload']['to'] === 'user@example.com';
} );
```

### `assert_pushed_times()`

Überprüfe, ob ein Job exakt so oft übergeben wurde wie erwartet.

```php
$this->fake->assert_pushed_times( SendEmailJob::class, 3 );
```

### `assert_not_pushed()`

Überprüfe, ob ein Job nie ausgeführt wurde.

```php
$this->fake->assert_not_pushed( DeleteAccountJob::class );
```

### `assert_nothing_pushed()`

Überprüfe, ob überhaupt keine Jobs ausgeführt wurden.

```php
public function test_no_jobs_on_invalid_input(): void {
    $this->fake = Queuety::fake();

    process_input( '' ); // invalid, should not dispatch anything

    $this->fake->assert_nothing_pushed();
}
```

## Batches überprüfen

### `assert_batched()`

Überprüfe, ob ein Batch ausgeführt wurde. Optional kannst du einen Callback übergeben, um nach Batch-Inhalten zu filtern.

```php
$this->fake->assert_batched();

$this->fake->assert_batched( function ( array $batch ) {
    return count( $batch['jobs'] ) === 3;
} );
```

Der Callback erhält ein Array mit den Schlüsseln `jobs` und `options`.

## Übergebene Jobs untersuchen

Mit `pushed()` rufst du alle aufgezeichneten Ausführungen für eine bestimmte Klasse ab, mit `batches()` alle aufgezeichneten Batches.

```php
$emails = $this->fake->pushed( SendEmailJob::class );
// [ ['handler' => '...', 'payload' => [...], 'queue' => 'default', 'instance' => null], ... ]

$batches = $this->fake->batches();
// [ ['jobs' => [...], 'options' => [...]], ... ]
```

## Zwischen Tests zurücksetzen

Rufe `reset()` für den Fake auf, um alle aufgezeichneten Jobs und Batches zu löschen, ohne eine neue Instanz zu erstellen.

```php
$this->fake->reset();
```

Oder rufe `Queuety::reset()` auf, um den Fake und seinen gesamten internen Zustand vollständig abzubauen.

## Vollständiges Beispiel

```php
use PHPUnit\Framework\TestCase;
use Queuety\Queuety;

class OrderWorkflowTest extends TestCase {
    private \Queuety\Testing\QueueFake $fake;

    protected function setUp(): void {
        $this->fake = Queuety::fake();
    }

    protected function tearDown(): void {
        Queuety::reset();
    }

    public function test_order_dispatches_payment_job(): void {
        $order = create_order( [ 'total' => 99.99 ] );

        $this->fake->assert_pushed( ProcessPaymentJob::class, function ( array $job ) use ( $order ) {
            return $job['payload']['order_id'] === $order->id;
        } );
        $this->fake->assert_not_pushed( RefundJob::class );
    }

    public function test_bulk_import_dispatches_batch(): void {
        start_bulk_import( $rows );

        $this->fake->assert_batched( function ( array $batch ) use ( $rows ) {
            return count( $batch['jobs'] ) === count( $rows );
        } );
    }

    public function test_nothing_dispatched_without_data(): void {
        process_empty_queue();

        $this->fake->assert_nothing_pushed();
    }
}
```
