Software testing is a key aspect of writing an high-quality code, and helps ensure that any future changes don’t unexpectedly break anything. Automation increases the repeatability of this task and is easily applied to Laravel.
Many modern web apps use email to send welcome information or notifications to users based upon certain events. Even with a well setup test environment, you will want to stop possible hundreds or thousands of test emails being sent. And there is an easy solution.
Mocking
A Mock Object is designed to simulate the behaviour of the real object but with out the actual functionality. It enables you to place it in many states to test behaviour in cases which you hope would never occur in production and are difficult to replicate in a test environment.
Laravel documentation often refers to Mocking as Faking. They are not technically the same thing, but that is an argument where the two sides are never going to agree. For this purpose, however, the two names are analogous.
Scenario
Lets say you are using Laravel’s user model with Email Verification. This was introduced in 5.7 to enable the protection of routes against users who may have registered but have not got a valid email address. i.e. Spam.
When a user registers, they should automatically be sent an email via the listener (I shall cover over-riding this listener in a separate post). You could just setup mailtrap.io or similar and see the results for yourself, but a phpunit test is more repeatable.
Faking Laravel Mail
As with much of Laravel, faking mail in a test case is simplicity itself.
use Illuminate\Auth\Notifications\VerifyEmail; use Illuminate\Support\Facades\Mail; public function testNewUserEmail() { // Setup the mock object Mail::fake(); // Call your business logic or factory $user = factory(User::class)->create(); // Test that the email has been sent Mail::assertSent(VerifyEmail::class); }
In the above example, the assertion is that a mailable
of the VerifyEmail
class was sent. If you use queues instead of direct sending, then you would replace Mail::assertSent()
with Mail::assertQueued()
.
There are also some inverse assertions – Mail::assertNotSent()
and Mail::assertNotQueued()
.