My team at Spatie is currenlty building Mailcoach, a solution to self host your e-mail newsletter. Mailcoach can be used a stand alone software or as a Laravel package. Subscribe now at Mailcoach to get a notification as soon as we release it.

Improving assertions on Laravel fakes

Original – by Freek Van der Herten – 4 minute read

Laravel has some cool fakes that can help you with testing your code. In this short blog post, I'd like to show you a little tip on how to get better feedback when a test that contains such a fake fails.

How to use a fake

Let's start with an example of a fake. You can skip to the next section if you've already worked with fakes.

Imagine your application sends a mail. You want to test if that mail is being sent correctly. The first step would be to set up the fake. Laravel makes this incredibly easy. Here's what you need to do:

use Illuminate\Support\Facades\Mail;

// inside a PHPUnit test class

/** @test */
public function this_is_your_test() 
{
     Mail::fake();
}

That fake method will swap the real mailer (that Laravel already set up) in the IoC container by a fake one. That fake one will not send the mail.

With this in place, you can test if a mail has been sent. You have to pass your mailable class to assertSent.

use Illuminate\Support\Facades\Mail;

/** @test */
public function this_is_your_test() 
{
     Mail::assertSent(OrderShipped::class);
}

Improving assertions on fakes

That assertSent method accepts a callable as a second argument. That callable will receive the mailable. In that callable, you can use methods like hasTo, hasCc to assert that the mailable is configured correctly. The docs contain the following example:

 // Assert a message was sent to the given users...
 Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
     return $mail->hasTo($user->email) &&
            $mail->hasCc('...') &&
            $mail->hasBcc('...');
 });

Now, the test only passes when that callable returns true. Nice!

But what if for some reason that callable doesn't return false? The failed test will output a message, not unlike this one:

The expected [OrderShipped::class] mailable was not sent. 

The problem here is that it's not clear if the to, cc or bcc is not correct. Let's improve that.

Probably you're using testing the mails inside of a PHPUnit test. Instead of just having one return statement in the callable, let's use PHPUnit assertions.

Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
   $this->assertTrue($mail->hasTo($user->email));
   $this->assertTrue($mail->hasCc('...'));
   $this->assertTrue($mail->hasBcc('...'));

   return true;
});

Sure, it's a bit more code to type. But with these assertions in place, a failing test will now also report the line number of the failed assertion, so you immediately know if either to, cc or bcc didn't contain the expected addresses.

You could opt to pass a custom message as a second argument to assertTrue. That message will be displayed when the assertion fails.

Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
   $this->assertTrue($mail->hasTo($user->email), 'Unexpected to');
   $this->assertTrue($mail->hasCc('...'), 'Unexpected cc');
   $this->assertTrue($mail->hasBcc('...'), 'Unexpected bcc');

   return true;
});

In conclusion

Laravel's fakes are fantastic. In this post, we've only used the mail specific one. But there are also fakes available for events, notifications, queues, ... Most of the assert methods on these fakes accept a callable as a second argument. Here's a real life refactor from returning a boolean to using assertions.

You can make a failing test much more readable buy not just returning a boolean in the callables you pass, but to use PHPUnit assertion methods inside of them.

Have fun testing!

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

swapnilsarwe liked on 25th September 2019
Mike liked on 25th September 2019
Luis Macias liked on 25th September 2019
Малєєв Андрій liked on 25th September 2019
winnipass adam liked on 25th September 2019
winnipass adam retweeted on 25th September 2019
B. Mohamed liked on 25th September 2019
B. Mohamed retweeted on 25th September 2019
Fahad Khan 💻 liked on 25th September 2019
keinan hasibuan liked on 25th September 2019
Scorp974 liked on 25th September 2019
Tanzania Developers Society retweeted on 25th September 2019
Luis Troya liked on 25th September 2019
Tanzania Developers Society liked on 25th September 2019
Alex Pierre liked on 25th September 2019
Diego Lorenzo liked on 25th September 2019
Trường Phúc Võ liked on 25th September 2019
Muhammad Sumon Molla Selim liked on 25th September 2019
Jordan Hall retweeted on 25th September 2019
Mickaël Isaert liked on 25th September 2019
Jordan Hall liked on 25th September 2019
Ivan Radunovic liked on 25th September 2019
David Cottila retweeted on 25th September 2019
Antério Vieira liked on 25th September 2019
Roman Pronskiy liked on 25th September 2019
Paul Redmond 🇺🇸 retweeted on 24th September 2019
PHP Synopsis retweeted on 24th September 2019
Sohail Ahmad replied on 24th September 2019
Awesome
Matt Kingshott 🧐 liked on 24th September 2019
Lee Overy liked on 24th September 2019
Salman Zafar liked on 24th September 2019
Ferdinand AMOI liked on 24th September 2019
technomike retweeted on 24th September 2019
Njogu Amos liked on 24th September 2019
mahmod liked on 24th September 2019
Oliver Nybroe liked on 24th September 2019
Hussam Fatahi liked on 24th September 2019
ダビッド トレス liked on 24th September 2019
ダビッド トレス retweeted on 24th September 2019
Myroslav retweeted on 24th September 2019
Adrian Nürnberger 🐙 liked on 24th September 2019
Matthew Poulter liked on 24th September 2019
⌥ os 📱 eclectic dev liked on 24th September 2019
Brad Madigan liked on 24th September 2019
Alex Rusin liked on 24th September 2019
Jimmy Lipham liked on 24th September 2019
Ruslan liked on 24th September 2019
ArielSalvadorDev liked on 24th September 2019
dhlevo liked on 24th September 2019
Cyril de Wit liked on 24th September 2019
ArielSalvadorDev retweeted on 24th September 2019
ahgood liked on 24th September 2019
Felipe 🍕 liked on 24th September 2019
Miguel Orellana liked on 24th September 2019
Andrés Santibáñez liked on 24th September 2019
Jeffrey Angenent liked on 24th September 2019
Tomáš Máčala liked on 24th September 2019
Scott Zirkel liked on 24th September 2019
Mazedul Islam Khan liked on 24th September 2019
Syl liked on 24th September 2019
Simon Kollross liked on 24th September 2019
Benjamin Crozat replied on 24th September 2019
Always done that. :)
Niels liked on 24th September 2019
Ⓜ️ fuz liked on 24th September 2019
Luis Jesus liked on 24th September 2019
Stefan Beierl liked on 24th September 2019
Guus liked on 24th September 2019
Victor Avelar replied on 24th September 2019
I know where this is coming from now 😅
Günther Debrauwer liked on 24th September 2019
Brian Rizzo liked on 24th September 2019
James Healey 🌠 liked on 24th September 2019
Jason Morton liked on 24th September 2019
QiroLab retweeted on 24th September 2019
QiroLab liked on 24th September 2019
Miguel Piedrafita 🛸 liked on 24th September 2019
Sascha Kliche liked on 24th September 2019
John Braun replied on 24th September 2019
Nice tip 👍 I’ll directly start using that 😎
John Braun liked on 24th September 2019
oussama.tn liked on 24th September 2019
Christoph Rumpel 🤠 liked on 24th September 2019
PheRum liked on 24th September 2019
Christoph Rumpel 🤠 retweeted on 24th September 2019
oussama.tn retweeted on 24th September 2019
Ramiro Varandas Jr liked on 24th September 2019
. liked on 24th September 2019
Maxime liked on 24th September 2019
Vishwanath liked on 24th September 2019
thisiskelvin liked on 24th September 2019
LUQMAN liked on 24th September 2019
pxgamer liked on 24th September 2019
Roman Pronskiy liked on 12th July 2019
Amitav Roy liked on 12th July 2019
Chin Leung liked on 10th July 2019
Simon Jønsson liked on 10th July 2019
Stace liked on 9th July 2019
Mattia Migliorini liked on 9th July 2019
Gábor Juhász liked on 9th July 2019
Carlos Abrisqueta retweeted on 9th July 2019
Harish Patel liked on 9th July 2019
Dainius liked on 9th July 2019
Michaël De Boey replied on 9th July 2019
Awesome addition! 🔥👊
Spatie retweeted on 9th July 2019
ArielSalvadorDev liked on 9th July 2019
JOSIAH YAHAYA liked on 9th July 2019
Osmar Alves liked on 9th July 2019
Axel Pardemann liked on 9th July 2019
Matt Wohler liked on 9th July 2019
Muhammad Ali Shah retweeted on 9th July 2019
Sokkary liked on 9th July 2019
Alex liked on 9th July 2019
Michaël De Boey liked on 9th July 2019
Sidrit Trandafili retweeted on 9th July 2019
swapnilsarwe liked on 9th July 2019
Chris Duell liked on 9th July 2019
Dries Vints retweeted on 9th July 2019
Ali Salah liked on 9th July 2019
Kevin Woblick liked on 9th July 2019
Célien Boillat🇨🇭 replied on 9th July 2019
With a hint of Hide the Pain Freek, maybe.
usman arshad replied on 9th July 2019
same herer, hahahh
Bernardo liked on 9th July 2019
De Belser Arne liked on 9th July 2019
James Mills liked on 9th July 2019
Ashfaq H Ahmed replied on 9th July 2019
Hahaha
Ashfaq H Ahmed liked on 9th July 2019
Vaibhavraj Roham liked on 9th July 2019
Aaron Parecki liked on 9th July 2019
pxgamer retweeted on 9th July 2019
Frederick Vanbrabant replied on 9th July 2019
When he arrives in Brooklyn.
pxgamer liked on 9th July 2019
Jos Kolenberg liked on 9th July 2019
Jose Antonio Rojas liked on 9th July 2019
Mazedul Islam Khan liked on 9th July 2019
Tom Martin liked on 9th July 2019
Andy Pattynama liked on 9th July 2019
Andre Sayej liked on 9th July 2019
Célien Boillat🇨🇭 replied on 9th July 2019
No, this is Happy Freek
Christoph Rumpel 🤠 replied on 9th July 2019
I still need to get used to the new photo. Can't handle such huge changes well 😬 is it still you Freek?
Ilya Sakovich liked on 9th July 2019
Peyman Goldasteh 🌀 liked on 9th July 2019
[object Object] retweeted on 9th July 2019
Justin Reasoner liked on 9th July 2019
Mark Myers liked on 9th July 2019
Sam Snelling liked on 9th July 2019
Vladyslav liked on 9th July 2019
ダビッド トレス liked on 9th July 2019
Parker McMullin liked on 9th July 2019
😸 liked on 9th July 2019
Lucas Fiege retweeted on 9th July 2019
Ed Grosvenor liked on 9th July 2019
Ihab liked on 9th July 2019
bcrypt retweeted on 9th July 2019
Spatie replied on 9th July 2019
Testing webmentions 😬
Full Stack Europe liked on 9th July 2019
Brian liked on 9th July 2019
Christoph Vigano liked on 9th July 2019
æbóng retweeted on 9th July 2019
Spatie liked on 9th July 2019
Amir Ahmic liked on 9th July 2019
æbóng liked on 9th July 2019
Florian Voutzinos ⚡ liked on 9th July 2019
Jason Kenyon liked on 8th July 2019