How can I test next logic in ONE Laravel test
- When I make a POST request with valid data
- Email was sent
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)