boptom's avatar

How to test Job Chaining in Laravel 5.5?

I have applied Job Chaining to an event in Laravel 5.5. I can check if the first job in the chain is being dispatched via:

Queue::assertPushedOn(FirstJob::class)

Is there a way to check that the rest of the jobs in the chain will be dispatched too?

0 likes
8 replies
ChristophHarms's avatar

If you have:

Job1 --dispatches--> Job2 --dispatches--> Job3 --dispatches--> Job4,

you just test it from the inside out. You write a test which verifies that Job3 dispatches Job4. Then a test which verifies that Job2 dispatches Job3, and finally a test which verifies that Job1 dispatches Job2. Then, in your integration test you just verify that Job1 is being dispatched and you can be sure that the whole Job Chain works as it should.

PS: If you dont's specify a queue, there's no need to use Queue::assertPushedOn(), it's sufficient to use Queue::assertPushed().

PPS: this really has nothing to do with a specific Laravel version or even Laravel at all, so maybe you could change the Question title to "How to test job chaining", so others can find this thread even when they're looking for other Laravel versions.

1 like
boptom's avatar

@ChristophHarms Sorry, I should have added more information. I'm using the job chaining functionality introduced in 5.5.

https://laravel.com/docs/5.5/queues#job-chaining

https://medium.com/@taylorotwell/weekend-laravel-improvements-26d0d230e48f

JobA::dispatch($obj)->chain([
    new JobB($obj),
    new JobC($obj),
]);

From what I can gather, JobB will only dispatch after JobA is completed. Similarly for JobC after JobB.

Unless I'm missing something I don't think I can test this from the inside out as the job chaining is not in the job class itself.

I want my tests to show JobA, JobB and JobC all dispatch.

I also want tests to intentionally throw errors in JobB for certain conditions, then assert JobC doesn't dispatch.

And thank you for the different between Queue::assertPushedOn() and Queue::assertPushed(). I always get them mixed up!

1 like
ChristophHarms's avatar
Level 18

Oh, I see, I misunderstood that indeed, sorry. I hadn't heard of this feature until now, so I can't really help you, but from what you write, I think you're right: This can't be tested the way I described.

But after reading this article from Taylor Otwell on medium.com, I think you should not test this. It is a feature from the framework you are using and in general, you should work under the assumption that the 3rd party stuff you are using works as expected.

You wouldn't bother to unit-test any of ImageMagick's methods just because you use it in your applications, because the tests for ImageMagick are in the codebase of ImageMagick and nothing to worry about for the lib user.

The whole point of the Job chaining feature (as I understood it), is that now the Jobs don't have to be aware that they're chained anymore.

PS: In fact, I just found the Integration test that verifies Job chaining works as expected: https://github.com/laravel/framework/blob/5.5/tests/Integration/Queue/JobChainingTest.php So all you have to test is that your Jobs do what they should. Testing the chaining itself is Taylors business. ;)

5 likes
boptom's avatar

@ChristophHarms Thank you for the reply. This has given me much clarity in terms of how to think about job testing!

1 like
AdrianB's avatar

I generally agree that testing an implementation is a bad idea, but when a chained job has no assertable side-effect, it doesn't fill you with confidence.

This is how I assert a job was chained:

Queue::fake();

// Some action

Queue::assertPushed(FirstJob::class, function ($job) {
    return collect($job->chained)->filter(function ($payload) {
        return strpos($payload, ChainedJob::class) !== false;
    })->isNotEmpty();
});
7 likes
ChristophHarms's avatar

@AdrianB Whoa, good catch! Very nice way to test that a job was chained. I think I'll use this in the future. :)

godbout's avatar

In my case, even if I trust that the chained job feature is working, I wanted to check whether I had forgotten to add a job in the chain or not. I didn't understand the code from AdrianB at first but after tinkering for a solution I ended up with the same. Thanks @adrianb!

1 like

Please or to participate in this conversation.