Laravel项目中使用PHPUnit+Mockery绕过第三方类方法抛出异常的测试问题
Laravel项目中使用PHPUnit+Mockery绕过第三方类方法抛出异常的测试问题
嗨,看了你的代码,我发现你现在的测试思路走偏啦!你当前是直接Mock了CompanyService自己的providePin方法,相当于完全跳过了这个方法的实际执行逻辑——但你真正想要的应该是:让CompanyService的providePin正常跑,只是绕过Mail::send抛出的异常,对吧?
问题出在你Mock错对象了:你需要Mock的是Mail这个静态类的send方法,而不是CompanyService的方法。下面给你修正后的测试代码,以及关键知识点解释:
正确的Mockery测试代码
use Mockery; use PHPUnit\Framework\TestCase; use App\Services\CompanyService; // 替换成你的实际命名空间 use App\Mail; // 替换成你的实际命名空间 class CompanyTest extends TestCase { // 测试结束后清理Mockery,避免污染其他测试 protected function tearDown(): void { parent::tearDown(); Mockery::close(); } // 测试邮件发送成功的场景 public function testProvidePinWhenMailSucceeds() { // 用Mockery创建Mail静态类的别名Mock,拦截静态方法调用 $mailMock = Mockery::mock('alias:' . Mail::class); $mailMock->shouldReceive('send') ->with(300386) // 匹配传入的pin参数 ->times(1) // 断言这个方法被调用1次 ->andReturnNull(); // 模拟方法正常执行,不抛出异常 // 实例化真实的CompanyService(我们要测试它的逻辑,不能Mock它本身) $companyService = new CompanyService(); $result = $companyService->providePin(300386); // 断言方法返回true,因为邮件发送成功 $this->assertTrue($result); } // 测试邮件发送失败(抛出异常)的场景 public function testProvidePinWhenMailFails() { // 模拟Mail::send抛出异常 $mailMock = Mockery::mock('alias:' . Mail::class); $mailMock->shouldReceive('send') ->with(300386) ->times(1) ->andThrow(new \Exception('Send mail error')); $companyService = new CompanyService(); $result = $companyService->providePin(300386); // 断言方法返回false,因为捕获到了异常 $this->assertFalse($result); } }
关键知识点说明
- 为什么不Mock CompanyService?:我们的测试目标是验证
CompanyService::providePin的try-catch逻辑是否正常工作,所以必须用真实的CompanyService实例,只Mock它依赖的外部服务(这里就是Mail类)。 Mockery::mock('alias:类名')的作用:这是Mockery专门用来处理静态类的语法,它会创建一个“别名类”来替代原有的静态类,这样所有对原静态类方法的调用都会被拦截到Mock对象上。- 必须清理Mock:在
tearDown方法里调用Mockery::close(),可以确保每个测试结束后清理Mock对象,避免影响其他测试用例的执行。
额外小提示(Laravel专属)
如果你是在Laravel框架内测试,其实可以用框架自带的Mail::fake()功能,比Mockery更简洁:
use Illuminate\Support\Facades\Mail; public function testProvidePinWhenMailSucceeds() { // 启用Mail的fake模式,拦截所有邮件发送 Mail::fake(); // 断言Mail::send被正确调用 Mail::shouldReceive('send')->with(300386)->once(); $companyService = new CompanyService(); $result = $companyService->providePin(300386); $this->assertTrue($result); }
备注:内容来源于stack exchange,提问作者VolkswagenLov
相关产品推荐
相关产品推荐

