有没有办法在Laravel 5中测试Mail?尝试了我在互联网上看到的唯一合法的Mock示例,但它似乎只适用于Laravel 4.目前的代码如下。
$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());
});
这是ApiClient.php的内容,最后一行是第155行,它在堆栈跟踪中显示。
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);
});
下面的是堆栈跟踪
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
此外,添加use Mockery;
会出现以下错误。
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
这让我感到沮丧几个小时,我已经在这里询问了SO。当他们决定升级到第5版时,Laravel在进行单元测试时没有直接支持测试邮件。
答案 0 :(得分:8)
让我花费一个下午更好的部分,但这最终是有效的 - 我通过了Closure并给了它一个Mockery对象
正在测试的代码:
$subject = "The subject";
Mail::send('emails.emailTemplate', ['user' => $user ],
function( $mail ) use ($user, $subject){
$mail -> to( $user -> email)
-> subject( $subject );
});
测试有效:
$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;
})
);
答案 1 :(得分:5)
刚从Laravel 5文档中发现,Facades的处理方式不同,并且有自己的测试方法。由于我使用的是Mail Facade,我根据Laravel 5文档页面中产生的微薄信息进行了一些实验。所以这里是我使用的代码
// 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']);
});
答案 2 :(得分:0)
Mail::shouldReceive('to')->once()->with('user email')
->andReturnUsing( function ($errorPasedToMailable) {
// here you are passing whatever type (array|model) to your Mailable
// in my case this is ['errorMessage' => 'some error']
$this->assertNotEmpty($errorPasedToMailable['errorMessage']);
// here result is your expected error message
$this->assertEquals($result, $errorPasedToMailable['errorMessage'])
});