Unittesting Laravel 5 Mail using Mock
Is there a way to check mail in Laravel 5? tried the only legitimate Mock example I see on the internet but it only seems to work with the current Laravel 4 code below.
$mock = Mockery::mock('Swift_Mailer');
$this->app['mailer']->setSwiftMailer($mock);
...some more codes here...
$mock->shouldReceive('send')->once()
->andReturnUsing(function($msg) {
$this->assertEquals('My subject', $msg->getSubject());
$this->assertEquals('foo@bar.com', $msg->getTo());
$this->assertContains('Some string', $msg->getBody());
});
this is the content of ApiClient.php, the last line is line 155, which is in the stack trace.
Mail::queue('emails.error', [
'error_message' => $error_message,
'request' => $request,
'stack_trace' => $stack_trace
], function ($message) use ($error_message) {
$message->to(env('MAIL_TO_EMAIL'), env('MAIL_TO_NAME'))->subject("[Project Error] " . $error_message);
});
below is the stack trace
Method Mockery_0__vendor_Swift_Mailer::getTransport() does not exist on this mock object
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php:285
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php:285
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php:150
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php:255
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php:126
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Queue/Jobs/SyncJob.php:42
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Queue/SyncQueue.php:25
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php:184
/Users/BON/WebServer/project/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:216
/Users/BON/WebServer/project/app/Libraries/ApiClient.php:155
/Users/BON/WebServer/project/app/Libraries/ApiClient.php:155
/Users/BON/WebServer/project/app/Libraries/ApiClient.php:174
/Users/BON/WebServer/project/tests/unit_tests/ApiClientUnitTest.php:43
adding use Mockery;
results in the following error.
PHP Warning: The use statement with non-compound name 'Mockery' has no effect in /Users/BON/WebServer/project/tests/unit_tests/ApiClientUnitTest.php on line 9
This has been frustrating me for hours to the point that I'm already asking about SO here. It's weird that Laravel doesn't have direct support for validating emails on delete when they decide to upgrade to version 5.
source to share
Waste me for the better part of the day, but this is finally what worked - I went through the closure and gave it a Mockery object
Checked code:
$subject = "The subject";
Mail::send('emails.emailTemplate', ['user' => $user ],
function( $mail ) use ($user, $subject){
$mail -> to( $user -> email)
-> subject( $subject );
});
Test that worked:
$subject = "The subject";
$user = factory(App\Models\User::class) -> create();
Mail::shouldReceive('send') -> once() -> with(
'emails.emailTemplate',
m::on( function( $data ){
$this -> assertArrayHasKey( 'user', $data );
return true;
}),
m::on( function(\Closure $closure) use ($user, $subject){
$mock = m::mock('Illuminate\Mailer\Message');
$mock -> shouldReceive('to') -> once() -> with( $user -> email )
-> andReturn( $mock ); //simulate the chaining
$mock -> shouldReceive('subject') -> once() -> with($subject);
$closure($mock);
return true;
})
);
source to share
Just discovered from the Laravel 5 documentation that Facades are handled differently and have their own testing methods. Since I am using the Mail Facade I experimented a bit with the meager information generated in the Laravel 5 documentation page so here's the code I used
// Mock the Mail Facade and assert that it receives a Mail::queue()
// with [whatever info you wish to check is passed. in my case, they're error contents]
Mail::shouldReceive('queue')->once()
->andReturnUsing(function($view, $view_params) {
$this->assertNotEmpty($view_params['error_message']);
$this->assertNotEmpty($view_params['request']);
$this->assertNotEmpty($view_params['stack_trace']);
});
source to share