I cant seem to get the Mail Facade to accept a ->with()
command for Testing.
This works:
Mail::shouldReceive('send')->once();
But this does not work:
Mail::shouldReceive('send')->with('emails.welcome')->once();
and neither does this:
Mail::shouldReceive('send')->with('emails.welcome', array(), function(){})->once();
and neither does this:
Mail::shouldReceive('send')->with('emails.welcome', array(), function($message){})->once();
All give the following error:
"No matching handler found for Illuminate\Mail\Mailer::send("emails.welcome", Array, Closure)"
So how can I test Mail to check what it is receiving?
Also - for bonus points - is it possible to test what Mail is doing inside the closure? i.e. can I check what $message->to()
is set to?
edit: my mail code:
Mail::send("emails.welcome", $data, function($message)
{
$message->to($data['email'], $data['name'])->subject('Welcome!');
});
To send your test email, start the application and access/send-mail path in your browser. Shortly after, you should see the email in Sandbox -> Inboxes. Alternatively, you can integrate Email Sandbox into your Laravel app via an API. For more details, refer to the API documentation.
Unlike traditional static method calls, facades may be mocked. We can mock the call to the static facade method by using the shouldReceive method, which will return an instance of a Mockery mock.
} The get method makes a GET request into the application, while the assertStatus method asserts that the returned response should have the given HTTP status code. In addition to this simple assertion, Laravel also contains a variety of assertions for inspecting the response headers, content, JSON structure, and more.
The code examples below assumes PHP 5.4 or newer - if you're on 5.3 you'll need to add $self = $this
before the following code and use ($self)
on the first closure, and replace all references to $this
inside the closure.
The simplest way is to mock the Swift_Mailer instance. You'll have to read up on what methods exist on the Swift_Message class in order to take full advantage of it.
$mock = Mockery::mock('Swift_Mailer');
$this->app['mailer']->setSwiftMailer($mock);
$mock->shouldReceive('send')->once()
->andReturnUsing(function(\Swift_Message $msg) {
$this->assertEquals('My subject', $msg->getSubject());
$this->assertEquals('[email protected]', $msg->getTo());
$this->assertContains('Some string', $msg->getBody());
});
Another way to solve this is to run assertions on the closure passed to Mail::send
. This does not look all that clean, and its error messages can be rather cryptic, but it works, is very flexible, and the technique can be used for other things as well.
use Mockery as m;
Mail::shouldReceive('send')->once()
->with('view.name', m::on(function($data) {
$this->assertContains('my variable', $data);
return true;
}), m::on(function($closure) {
$message = m::mock('Illuminate\Mailer\Message');
$message->shouldReceive('to')
->with('[email protected]')
->andReturn(m::self());
$message->shouldReceive('subject')
->with('Email subject')
->andReturn(m::self());
$closure($message);
return true;
}));
In this example, I'm running an assertion on the data passed to the view, and I'll get an error from Mockery if the recipient address, subject or view name is wrong.
Mockery::on()
allows you to run a closure on a parameter of a mocked method. If it returns false, you'll get the "No matching handler found", but we want to run assertions so we just return true. Mockery::self()
allows for chaining of methods.
If at any point you don't care what a certain parameter of a method call is, you can use Mockery::any()
to tell Mockery that it accepts anything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With