You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

额外注意事项

  1. 测试完成后,记得在测试类的tearDown方法中清理Mockery:
protected function tearDown(): void
{
    parent::tearDown();
    Mockery::close();
}
  1. 你的导出类存在一个小问题:$html变量在if (empty($html))判断前未定义,会触发Undefined variable错误,建议修正该逻辑。

内容的提问来源于stack exchange,提问作者sparkmix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:25:36