0

I want to use PHPUnit to exercise the queued job lifecycle when performing a job triggered by an API request.

EDIT: phpunit.xml has

    <env name="QUEUE_DRIVER" value="database"/>

There is a call from the frontend to an API that dispatches a job and immediately returns a response with the status (queued). This works fine when called from the frontend Javascript.

Trying to test this same endpoint with PHPUnit, with a test that calls the same API endpoint, I see that the job does not appear in the 'jobs' table. Here is the test code (EDIT2):

    public function testJobStatusBasic()
    {
        $response = $this->post('/api/jobstatustest');

        $response->assertStatus(200);
        
        $response->assertJson([
            "data" => []
        ]);
    }

This returns as a pass, the API endpoint shown there inserts a test job which takes a few seconds to complete. At least, it does when the front-end calls it. Just not from PHPUnit. The idea is that I can add some subsequent GET calls to test the job status monitoring system.

With some logging, I can see that the Job constructor is called. No errors are seen, there is just no job in the database when the call returns.

Setting QUEUE_CONNECTION to "sync" works fine executing the job synchronously, delaying the return of the above POST, but this is not what I want to test here, where I specifically want to run the entire job lifecycle. Or is this impossible / not intended to work like this?

Dan
  • 1,249
  • 2
  • 16
  • 31
  • Are you sure you ar setting the queue driver correctly? I remember me having this problem - forgetting to change the queue driver inside the phpunit.xml file – cdruc Apr 20 '21 at 11:44
  • Why do you want to have it as `database` instead of `sync` ? If you are trying to create something via a controller, and it triggers a job, you don't have to see if the job worked, you have to fake the queue with `Queue::fake()` and then you can assert if the job got dispatched, and then create other test that will assert if what it is doing is correct or not... Explain more what you are exactly doing so we can guide you. – matiaslauriti Apr 20 '21 at 21:52
  • @matiaslauriti I want to run a test that tries the entire job lifecycle, i.e. submit it, monitor the status as it executes, possibly including retries, then fetch the status once its finished. I can do this with a system test where a front-end tool like Cypress exercises the API from the browser. But it would be more self-contained to have a backend test do it all. – Dan Apr 22 '21 at 16:21
  • @Dan Oh yes, never use "external" triggers to test backend code, always use backend to test it. You can super easily test jobs/queues. You just have to make sure that the [job](https://laravel.com/docs/8.x/mocking#queue-fake) is being dispatched, so you can assert that it got dispatched and even with what data. In other test (surely unit test) you test that the job is doing what you expected it to do, how ? You just dispatch it in your test and assert that any expected data changed, super easy and straightforward ! – matiaslauriti Apr 22 '21 at 18:25
  • @matiaslauriti so any ideas on why the job does not get dispatched (only) in the PHPUnit environment? The __construct() gets called but nothing appears in the 'jobs' table. – Dan Apr 24 '21 at 07:03
  • @Dan yes, that is because you are not using `sync` – matiaslauriti Apr 24 '21 at 14:19
  • @Dan have a look at [this answer](https://stackoverflow.com/questions/67244439/problem-with-testing-database-laravel-7-x/67245357#67245357), hope it helps you understand testing a little more. – matiaslauriti Apr 24 '21 at 19:31
  • @matiaslauriti I've added the test code EDIT2 which is of the same form as the answer you reference. I want to add some subsequent GETS to the test code to monitor the jobs progression and completion. Are you saying that it is expected that the job will not get created if I use "database" instead of "sync"? I.e. that what I am trying to do is impossible with PHPUnit? – Dan Apr 26 '21 at 06:06
  • Yes, you have to use `sync`, if you don't want it to run, you have to use `Queue::fake()` – matiaslauriti Apr 26 '21 at 18:20
  • Just to be absolutely sure - if I want to test the complete job status progression and monitoring, there is no way to do it from PHPUnit, I will have to test it from the front end? – Dan Apr 28 '21 at 06:14

1 Answers1

0

Here are some tips.

  1. set up your database connection in .env.testing.

    DB_DATABASE=db_test
    DB_USERNAME=user
    DB_PASSWORD=password
    
  2. in your phpunit.xml set queue_connection to the database

         <server name="QUEUE_CONNECTION" value="database"/>
    
  3. in your phpunit.xml again, make sure you are using the correct database driver. it should be the same as what you have in your .env.testing.

               <server name="DB_CONNECTION" value="mysql"/> 
    
  • Thanks, I tried these but same behavior - job construct is called, but never the handler, and nothing in the jobs table. – Dan Oct 14 '22 at 09:52