Testing listeners with Queue :: fake ()

My Laravel 5.5 app has a Product model. The Product model has a dispatchesEvents property, which looks like this:

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

I also have a listener called CreateProductInMagento that displays in the ProductCreated event in EventServiceProvider . This listener implements the ShouldQueue interface.

When a product is created, the ProductCreated event is fired, and the CreateProductInMagento listener is queued and fired.

Now I'm trying to write a test for all of this. Here is what I have:

 /** @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); } 

But I get the error message The expected [App\Listeners\Magento\Product\CreateProductInMagento] job was not pushed. .

How to check listeners waiting to listen using the Laravel Queue::fake() method?

+5
source share
2 answers

The problem is that the listener is not a queued job. Instead, there is the Illuminate\Events\CallQueuedListener , which is queued and in turn calls the corresponding listener when it is resolved.

So, you can make your statement as follows:

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

Running artisan queue:work will not solve the problem, because when testing Laravel is configured to use the sync driver, which simply runs tasks synchronously in your tests. I am not sure why the work is not being pushed, although I would suggest that this is due to the fact that Laravel handles events differently in tests. Regardless of whether there is a better approach you can take to write your own tests, which should both fix the problem and make your code more extensible.

In your ProductTest , instead of testing this a_created_product_is_pushed_to_the_queue_so_it_can_be_added_to_magento , you should just check that the event is fired. Your ProductTest doesn't care what a ProductCreated event is; this is a ProductCreatedTest task. Thus, you can use Event Faking to slightly modify the test:

 /** @test */ public function product_created_event_is_fired_upon_creation() { Event::fake(); factory(Product::class)->create(); Event::assertDispatched(ProductCreated::class); } 

Then create a new ProductCreatedTest to unit test your ProductCreated event. Here you should put the statement that the job is queued:

 /** @test */ public function create_product_in_magento_job_is_pushed() { Queue::fake(); // Code to create/handle event. Queue::assertPushed(CreateProductInMagento::class); } 

This has the added benefit of making your code easier to change in the future, since your tests now more closely monitor the practice of only testing the class for which they are responsible. In addition, it should solve the problem that you encounter when events released from the model are not waiting for your assignments.

+1
source

Source: https://habr.com/ru/post/1274480/


All Articles