How can I test next logic in ONE Laravel test
In a code base it looks like this
// controller
public function store(StoreOrderRequest $request)
{
OrderCreated::dispatch($request->validated());
}
SendEmailToUser
listener (which implements ShouldQueue
interface, queue connection - database
) listens OrderCreated
event
// SendEmailToUser listener
public function handle(OrderCreated $event)
{
Mail::send(new OrderCreatedMail($event->data));
}
For now next two tests works fine - first I'll check if event was dispatched, then check if corresponding listener was attached and finally check the logic for listener itself
test('event dispatched', function () {
Event::fake();
$this->post(...);
Event::assertDispatched(OrderCreated::class);
Event::assertListening(OrderCreated::class, SendEmailToUser::class);
});
test('mail sent', function () {
Mail::fake();
(new SendEmailToUser())->handle(new OrderCreated($data));
Mail::assertSent(OrderCreatedMail::class);
});
However my question is can I refactor those into ONE test something like
Something::fake();
// When I make a POST request
$this->post(...);
// Email was sent
Mail::assertSent(OrderCreatedMail::class);
I want my test to not depend on logic inside of the "black box" but to take care only of its result. Cause maybe I'll change implementation for sending mails and the only thing for now I care is was the mail sent or not (let's say I'll change my controller method to send mails directly or something else - tests will fail while real app logic "when send POST request with correct data - then email was sent" still be valid)
You definitely can, and should not be an issue (no code-issues), but remember that you should be only testing ONE thing per test. So, my personal recommendation, after some years of experience with Laravel and testing is:
test('listener attached to event', function () {
/**
* You should not need to Event::fake(); but I cannot remember,
* test it this way first
*/
Event::assertListening(OrderCreated::class, SendEmailToUser::class);
});
Check out my StackOverflow profile, maybe there is another solution in there related to testing that is of help for you!