Laravel单元测试Mock DomPDF报错,如何测试异常处理逻辑?
问题:Mock Barryvdh\DomPDF\Facade时触发致命错误,无法测试异常处理
我在对基于Barryvdh\DomPDF\Facade开发的PDF导出类做单元测试时,尝试Mock PDF抛出异常来验证异常处理逻辑,结果遇到了致命错误:
Fatal error: Cannot redeclare Mockery_0_Barryvdh_DomPDF_Facade_Pdf::shouldReceive() in \vendor\mockery\mockery\library\Mockery\Loader\EvalLoader.php(24) : eval()'d code on line 997
怀疑是Mock方式不对,想知道正确的测试方法。
当前Mock代码:
use Mockery; Mockery::mock(\Barryvdh\DomPDF\Facade\Pdf::class)->shouldReceive('loadHTML')->andThrow(new \Exception('Mocked PDF Load Error'));
导出类代码:
namespace App\Exports; use Illuminate\Support\Str; use Illuminate\Support\Facades\Log; use Barryvdh\DomPDF\Facade\Pdf; class DataPdfExport{ protected $data; public function __construct($data) { $this->data = $data; } public function export() { try { $randomSuffix = Str::random(8); if (empty($html)) { $html = view('exports.data-pdf', ['data' => $this->data])->render(); } $pdf = PDF::loadHTML($html); $file = 'data'. now()->format('Ymd') . '-' . $randomSuffix. '.pdf'; return ['error' => false, 'pdf' => $pdf, 'file' => $file]; } catch (\Exception $e) { Log::error('ExcelExport Error: '.$e->getMessage()); return ['error' => true, 'message' => 'Failed pdf export. Please try again later.']; } } }
解决方法
问题根源
你直接Mock Facade类本身是错误操作。Laravel的Facade本质是静态代理,它指向容器中的实际服务实例,直接Mock Facade类会触发类重复声明的致命错误。正确的做法是Mock Facade对应的底层服务类,或者使用Laravel自带的Facade Mock机制。
正确Mock方式
方式一:使用Laravel自带的Facade Mock(推荐)
Laravel的Facade已经内置了Mock支持,直接调用shouldReceive即可:
use Barryvdh\DomPDF\Facade\Pdf; // 在测试方法中 Pdf::shouldReceive('loadHTML') ->once() // 可选,断言该方法被调用一次 ->andThrow(new \Exception('Mocked PDF Load Error')); // 执行导出逻辑 $export = new \App\Exports\DataPdfExport($testData); $result = $export->export(); // 验证异常处理结果 $this->assertTrue($result['error']); $this->assertEquals('Failed pdf export. Please try again later.', $result['message']);
方式二:用Mockery替换容器中的服务实例
直接Mock底层的Barryvdh\DomPDF\PDF类,并绑定到Laravel容器:
use Mockery; use Barryvdh\DomPDF\PDF; // 创建Mock实例 $pdfMock = Mockery::mock(PDF::class); $pdfMock->shouldReceive('loadHTML') ->andThrow(new \Exception('Mocked PDF Load Error')); // 将Mock绑定到容器,替换原服务 app()->instance(PDF::class, $pdfMock); // 执行导出并验证结果 $export = new \App\Exports\DataPdfExport($testData); $result = $export->export(); $this->assertTrue($result['error']);
额外注意事项
- 测试完成后,记得在测试类的
tearDown方法中清理Mockery:
protected function tearDown(): void { parent::tearDown(); Mockery::close(); }
- 你的导出类存在一个小问题:
$html变量在if (empty($html))判断前未定义,会触发Undefined variable错误,建议修正该逻辑。
内容的提问来源于stack exchange,提问作者sparkmix
相关产品推荐
相关产品推荐

