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.

+3


source to share


2 answers


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;
        })
    );

      

+6


source


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']);
        });

      

+5


source







All Articles