
# Тестирование

Queuety предоставляет класс `QueueFake`, который заменяет реальную очередь хранилищем в памяти. Отправленные задачи записываются вместо сохранения в базе данных; `create_batch()` также хранит метаданные пакетов в памяти. Это позволяет проверять отправку задач, не запуская рабочие процессы и не записывая данные в базу. При отправке по имени обработчика он по-прежнему определяется через реестр, поэтому перед отправкой строкового имени обработчика вызовите `Queuety::init()`; экземпляры `Contracts\Job`, `chain()`, `create_batch()` и `batch()` работают без этого.

## Настройка подмены очереди

Вызовите `Queuety::fake()` в начале теста. Метод возвращает экземпляр `QueueFake`, который записывает все последующие отправки задач.

```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()` создает новый `QueueFake` и подключает его к фасаду `Queuety`. `Queuety::dispatch()` и `Dispatchable::dispatch()` записывают добавленные задачи. `Queuety::chain()` записывает каждую задачу цепочки как обычную отправку в порядке диспетчеризации. `Queuety::create_batch()` записывает и добавленные задачи, и метаданные пакета, используемые `assert_batched()`. `Queuety::batch()` записывает добавленные задачи, но не создает поддельные метаданные пакета.

Вызовите `Queuety::reset()` в `tearDown()`, чтобы сбросить подмену между тестами. Метод очищает все состояние фасада, поэтому вызовите `Queuety::init()` снова, если в следующем тесте нужна реальная очередь.

## Проверка отправки задач

### `assert_pushed()`

Проверьте, что задача определенного класса была отправлена хотя бы один раз.

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

Передайте необязательную функцию обратного вызова, чтобы отфильтровать данные по содержимому или другим атрибутам. Функция получает массив записанных данных задачи с ключами `handler`, `payload`, `queue` и `instance`. Для задач, отправленных через фасад или трейт `Dispatchable`, значение `instance` равно `null`, поэтому выполняйте сопоставление по `handler` и `payload`.

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

### `assert_pushed_times()`

Проверьте, что задача была добавлена ровно указанное количество раз.

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

### `assert_not_pushed()`

Проверьте, что задача ни разу не была отправлена.

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

### `assert_nothing_pushed()`

Проверьте, что задачи вообще не отправлялись.

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

## Проверка пакетов

### `assert_batched()`

Проверьте, что пакет был отправлен. При необходимости передайте функцию обратного вызова для фильтрации по содержимому пакета.

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

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

Функция обратного вызова получает массив с ключами `jobs` и `options`.

## Просмотр добавленных задач

Используйте `pushed()`, чтобы получить все записанные отправки задач указанного класса, и `batches()`, чтобы получить все записанные пакеты.

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

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

## Сброс между тестами

Вызовите `reset()` для подмены, чтобы очистить все записанные задачи и пакеты без создания нового экземпляра.

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

Или вызовите `Queuety::reset()`, чтобы полностью удалить подмену и все ее внутреннее состояние.

## Полный пример

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