MauroBaptista.com

Testing the object you pass in a mocked method

PHPUnit Test Laravel

Let's image we have a class:

1class EmailSender
2{
3 public function send(Email $email): void
4 {
5 // your implementation
6 }
7}

The Email class will hold the details to the email you want to send:

1class Email
2{
3 public string $template;
4 
5 public string $email;
6 
7 //...
8}

If you want to mock the EmailSender you can do something like this:

1...
2 
3class EmailSenderTest extends TestCase
4{
5 public function testEmailSender()
6 {
7 $this->instance(
8 EmailSender::class,
9 Mockery::mock(EmailSender::class, function (MockInterface $mock) {
10 $mock->shouldReceive('send')
11 ->withAnyArgs()
12 ->once();
13 })
14 );
15 
16 ...
17 }
18}

The approach above you are testing if the send message is called once, but you haven`t tested if the argument provided to the method has the correct data on it.

To add checks on the object as well, you can assert it in the with for a mocked object, as:

1...
2 
3class EmailSenderTest extends TestCase
4{
5 public function testEmailSender()
6 {
7 $this->instance(
8 EmailSender::class,
9 Mockery::mock(EmailSender::class, function (MockInterface $mock) {
10 $mock->shouldReceive('send')
11 ->with(Mockery::on(function (Email $email) {
12 $this->assertEquals('my-template', $email->template);
13 $this->assertEquals('[email protected]', $email->email);
14 })->once();
15 })
16 );
17 
18 ...
19 }
20}

This way your test is only going to pass if the Email class has expected template and email properties.