We continue discussing faking in the Laravel tests because, in many cases, we cannot directly replicate the actual scenario.
We cannot replicate the same identical scenario for Jobs that are dispatched into the queue since the queue jobs are executed later.
That's why we need to fake the queue mechanism. In this case, we will fake the Bus
to assert that the Job was actually fired and dispatched into the queue.
Imagine a scenario where you dispatch a Job to notify some users after a new product is created.
use App\Models\Product;use Illuminate\Http\Request;use App\Jobs\NewProductNotifyJob;use Illuminate\Http\RedirectResponse; class ProductController extends Controller{ // ... public function store(Request $request): RedirectResponse { $product = Product::create($request->all()); if ($request->hasFile('photo')) { $filename = $request->file('photo')->getClientOriginalName(); $request->file('photo')->storeAs('products', $filename); $product->update(['photo' => $filename]); } NewProductNotifyJob::dispatch($product); return redirect()->route('products.index'); } // ...}
The Job is straightforward: it only logs an info message.
use App\Models\Product;use Illuminate\Bus\Queueable;use Illuminate\Queue\SerializesModels;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable; class NewProductNotifyJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct(private readonly Product $product) {} public function handle(): void { info('Sending notification to everyone about ' . $this->product->name); }}
Now, we need to test that the Job was actually dispatched. The initial test looks like this:
use App\Models\User;use function Pest\Laravel\actingAs; beforeEach(function () { $this->user = User::factory()->create();}); test('product create job notification dispatched successfully', function () { actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); // Assert job was fired});
Similar to what we did with the Storage in the previous lesson, we must use the XXXXX::fake()
method. This time, we're using the Bus
facade.
use App\Models\User;use Illuminate\Support\Facades\Bus;use function Pest\Laravel\actingAs; beforeEach(function () { $this->user = User::factory()->create();}); test('product create job notification dispatched successfully', function () { Bus::fake(); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); // Assert job was fired});
Now, the Bus
facade has a method to assert that the Job was dispatched.
use App\Models\User;use App\Jobs\ProductPublishJob;use Illuminate\Support\Facades\Bus;use function Pest\Laravel\actingAs; beforeEach(function () { $this->user = User::factory()->create();}); test('product create job notification dispatched successfully', function () { Bus::fake(); actingAs($this->user) ->post('/products', [ 'name' => 'Product 123', 'price' => 1234, ]); Bus::assertDispatched(ProductPublishJob::class); });
Important notice: the test has passed, which means the Job was dispatched. But it doesn't prove that it was executed successfully, so we need to create separate tests to assert the result of those Jobs. But at least we know that it was fired and dispatched.