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

如何在Laravel中用PHPUnit测试Bus::chain()->catch()异常处理逻辑

测试Laravel链式任务的Catch代码块

问题场景

我正在使用PHPUnit编写测试,验证链式任务的调度逻辑,已经能通过Bus::assertChained()验证任务的链式结构,但遇到了一个问题:当链式任务中的某个任务抛出异常时,如何触发对应的catch()代码块,并断言$model->error字段会被更新?

示例业务代码:

Bus::chain([
    new JobOne($model),
    new JobTwo($model),
    new JobThree($model),
])
    ->catch(function (Throwable $e) use ($model) {
        $model->update([
            'error' => true,
        ]);
    })
    ->dispatch();

由于任务都是直接实例化的新对象,无法直接通过Mock模拟抛出异常,需要找到可行的触发方式。

解决方案

方法一:利用Bus Fake机制自定义任务行为

Laravel的Bus::fake()可以拦截任务执行,针对特定任务类设置自定义逻辑,强制抛出异常:

public function test_chain_catch_triggers_on_job_failure()
{
    $model = Model::factory()->create();

    // 指定JobTwo执行时抛出异常
    Bus::fake([
        JobTwo::class => fn ($job) => throw new Exception('Test exception'),
    ]);

    // 执行触发链式任务的业务逻辑(比如调用接口或方法)
    $this->post('/trigger-chain-job');

    // 验证catch块执行结果
    $model->refresh();
    $this->assertTrue($model->error);

    // 可选:验证链式任务的调度顺序
    Bus::assertChained([JobOne::class, JobTwo::class]);
}

方法二:给任务类添加测试专用异常开关

在任务类中添加静态属性,仅在测试环境下控制是否抛出异常:

修改JobTwo类:

class JobTwo implements ShouldQueue
{
    // 测试专用开关
    public static $throwTestException = false;

    public function __construct(public Model $model) {}

    public function handle()
    {
        // 仅在测试环境且开关开启时抛出异常
        if (self::$throwTestException && app()->environment('testing')) {
            throw new Exception('Test failure');
        }

        // 原任务业务逻辑
    }
}

测试代码:

public function test_catch_block_updates_model_on_failure()
{
    $model = Model::factory()->create();
    JobTwo::$throwTestException = true;

    // 调度链式任务
    Bus::chain([
        new JobOne($model),
        new JobTwo($model),
        new JobThree($model),
    ])->dispatch();

    // 验证模型字段更新
    $model->refresh();
    $this->assertTrue($model->error);

    // 重置开关,避免影响其他测试
    JobTwo::$throwTestException = false;
}

方法三:Partial Mock任务类的handle方法

使用PHPUnit的部分Mock功能,Mock任务类的handle方法使其抛出异常:

public function test_chain_job_failure_triggers_catch()
{
    $model = Model::factory()->create();

    // Partial Mock JobTwo,仅替换handle方法
    $this->partialMock(JobTwo::class, function ($mock) {
        $mock->shouldReceive('handle')
             ->andThrow(new Exception('Test error'));
    });

    // 调度链式任务
    Bus::chain([
        new JobOne($model),
        new JobTwo($model),
        new JobThree($model),
    ])->dispatch();

    // 验证模型状态
    $model->refresh();
    $this->assertTrue($model->error);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:05:15