Framework: Bus::fake($jobsToFake) doesn't execute the full chain when dispatched

Created on 21 Oct 2020  路  7Comments  路  Source: laravel/framework


  • Laravel Version: v8.10.0
  • PHP Version: 7.4.8
  • Database Driver & Version: N/A

Description:

I expected that when using Bus::fake($jobsToFake) in conjunction with Bus::chain([...])->dispatch(), the full chain would be executed, except for the jobs specified in $jobsToFake array.

Am I missing something?

Steps To Reproduce:

<?php

namespace Tests\Unit;

use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Bus;
use Tests\TestCase;


class BugReportTest extends TestCase
{
    public function testBusFake()
    {
        Bus::fake(['foobar']);

        Bus::chain([
            new Job("no problem -- job1"),
            // nothing below is executed.
            function() {
                logger("never executed");
            },
            new Job("never executed")
        ])->dispatch();
    }
}

class Job
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(string $s = null)
    {
        $this->s = $s;
    }

    public function handle()
    {
        logger($this->s);
    }
}

needs more info

Most helpful comment

Or, put whatever "external" work is done in some of those jobs behind another class that is injected into those jobs and can be mocked so that only the external work is mocked and not the jobs that call the external work service itself.

All 7 comments

Ping @themsaid

Can you paste the exact code and class names without names like foobar or placeholders?

Hi @taylorotwell . Thanks for replying.

I'm not sure what you mean. Anyways, I quick-started an empty project and pushed a more complete example here: https://github.com/lucaspottersky/laravel-fakebus-bugreport

Relevant commit: https://github.com/lucaspottersky/laravel-fakebus-bugreport/commit/043eac28b145dd9c2b6e591577452b692623d4ad

Let me know if there's anything else I can help.

Copying here:

<?php

namespace Tests\Unit;

use App\Jobs\FourJob;
use App\Jobs\OneJob;
use App\Jobs\ThreeJob;
use App\Jobs\TwoJob;
use Illuminate\Support\Facades\Bus;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    // Outputs:
    // testing.DEBUG: OneJob running...
    public function testWontRunAfterTwoJob()
    {
        Bus::fake([TwoJob::class]);

        Bus::chain([
            new OneJob(),
            new TwoJob(),
            new ThreeJob(),
        ])->dispatch();
    }

    // Outputs:
    // testing.DEBUG: OneJob running...
    // testing.DEBUG: TwoJob running...
    public function testWontRunAfterThreeJob()
    {
        Bus::fake([ThreeJob::class]);

        Bus::chain([
            new OneJob(),
            new TwoJob(),
            new ThreeJob(),
            new FourJob(),
        ])->dispatch();
    }
}

Yeah, I would expect that to be the case given how chains are implemented currently. When the job runs, it is responsible for firing off the next job in the chain. So, since a job in the middle is mocked... everything up to that point will run but since it is mocked it never runs and never fires off its chain.

Whether that's a "bug" or not I'm not sure 馃槄

I see. Well, any ideas how to work around?

In my use case the code under test uses Bus::chain with closures & job objects. So in my unit tests I wanted to fake the "external" objects and assert only the closures side-effects. 馃ズ

Probably not the answer you are looking for but _if it were me_ I would probably do the following:

  • Bus:fake() everything
  • Convert Closure chain jobs to classes
  • Assert the main job was dispatched with the chain of job classes you expect
  • Test the chain job classes separately in their own tests

Or, put whatever "external" work is done in some of those jobs behind another class that is injected into those jobs and can be mocked so that only the external work is mocked and not the jobs that call the external work service itself.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JamborJan picture JamborJan  路  3Comments

progmars picture progmars  路  3Comments

Fuzzyma picture Fuzzyma  路  3Comments

kerbylav picture kerbylav  路  3Comments

ghost picture ghost  路  3Comments