跳转到正文

测试

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() 会记录推送的任务,但不会创建模拟批次元数据。

在 tearDown() 中调用 Queuety::reset(),即可在测试之间清除模拟对象。它会清除所有门面状态,因此如果后续测试需要使用真实队列,请再次调用 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 trait 分发的任务,其 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();
    }
}