使用Queue :: fake()测试监听器

时间:2018-01-03 19:25:45

标签: php laravel unit-testing mocking

我的Laravel 5.5应用程序具有Product模型。 Product模型具有dispatchesEvents属性,如下所示:

/**
 * The event map for the model.
 *
 * @var array
 */
protected $dispatchesEvents = [
    'created' => ProductCreated::class,
    'updated' => ProductUpdated::class,
    'deleted' => ProductDeleted::class
];

我还有一个名为CreateProductInMagento的侦听器,它被映射到ProductCreated中的EventServiceProvider事件。该侦听器实现ShouldQueue接口。

创建产品时,会触发ProductCreated事件并将CreateProductInMagento侦听器推送到队列并运行。

我现在正在尝试为所有这些编写测试。这就是我所拥有的:

/** @test */
public function a_created_product_is_pushed_to_the_queue_so_it_can_be_added_to_magento()
{
    Queue::fake();

    factory(Product::class)->create();

    Queue::assertPushed(CreateProductInMagento::class);
}

但我收到The expected [App\Listeners\Magento\Product\CreateProductInMagento] job was not pushed.错误消息。

如何使用Laravel的Queue::fake()方法测试可排队的侦听器?

2 个答案:

答案 0 :(得分:9)

这里的问题是侦听器不是推送到队列的作业。相反,有一个Illuminate\Events\CallQueuedListener作业排队,并在解决后依次调用适当的侦听器。

所以你可以这样做你的断言:

Queue::assertPushed(CallQueuedListener::class, function ($job) {
    return $job->class == CreateProductInMagento::class;
});

答案 1 :(得分:1)

运行artisan queue:work无法解决问题,因为在测试时,Laravel配置为使用sync驱动程序,该驱动程序只在测试中同步运行作业。我不确定为什么这项工作没有被推动,尽管我猜它与Laravel在测试中处理事件的方式有所不同。无论如何,您可以采用更好的方法编写测试,既可以解决问题,也可以使代码更具扩展性。

ProductTest中,您应该只测试该事件是否被触发,而不是测试a_created_product_is_pushed_to_the_queue_so_it_can_be_added_to_magento。您的ProductTest并不关心ProductCreated事件是什么;这是ProductCreatedTest的工作。因此,您可以使用Event Faking稍微更改您的测试:

/** @test */
public function product_created_event_is_fired_upon_creation()
{
    Event::fake();

    factory(Product::class)->create();

    Event::assertDispatched(ProductCreated::class);
}

然后,创建一个新的ProductCreatedTest以对您的ProductCreated事件进行单元测试。这是您应该将作业推送到队列的断言:

/** @test */
public function create_product_in_magento_job_is_pushed()
{
    Queue::fake();

    // Code to create/handle event.

    Queue::assertPushed(CreateProductInMagento::class);
}

这样做的另一个好处是可以让您的代码在将来更容易更改,因为您的测试现在更加严格地遵循仅测试他们负责的类的做法。此外,它应该解决您从模型触发的事件不会排队工作的问题。