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?
<?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);
}
}
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:
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.
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.