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

如何测试修改ExceptionEvent的自定义Symfony事件监听器?

如何测试修改ExceptionEvent的Symfony事件监听器

我编写了一个Symfony事件监听器,它没有返回值,仅通过修改ExceptionEvent对象来设置JSON格式的异常响应,但不知道如何编写对应的测试代码,目前的测试代码卡在了验证环节。以下是我现有的测试代码和监听器实现:

现有测试代码

<?php

declare(strict_types=1);

namespace Tests\Unit\Listener;

use App\Listener\ExceptionListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class ExceptionListenerTest extends TestCase
{
    public function testWithValidExceptionEvent(): void
    {
        $event = new ExceptionEvent(
            $this->createMock(HttpKernelInterface::class),
            $this->createMock(Request::class),
            1,
            $this->createMock(\Throwable::class)
        );
        new ExceptionListener($event);

        // 卡在这里不知道怎么验证
    }
}

监听器实现代码

<?php

declare(strict_types=1);

namespace App\Listener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;

#[AsEventListener]
final class ExceptionListener
{
    public function __invoke(ExceptionEvent $event): void
    {
        $throwable = $event->getThrowable();

        $response = new JsonResponse([
            'message' => $throwable->getMessage(),
            'code' => $throwable->getCode()
        ]);

        $event->setResponse($response);
    }
}

解决方案

  • 修正监听器的调用方式:你的测试代码里直接用new ExceptionListener($event)是错误的,因为监听器的逻辑在__invoke方法里,正确的做法是先实例化监听器,再调用该方法传入事件对象。
  • 使用可预期的Throwable实例:不要用createMock(\Throwable::class),而是创建一个真实的异常实例,这样能明确控制getMessage()和getCode()的返回值,方便后续验证。
  • 验证Event对象的修改结果:调用监听器后,从ExceptionEvent中取出设置的响应,验证它的类型、内容是否符合预期。

修改后的完整测试代码

<?php

declare(strict_types=1);

namespace Tests\Unit\Listener;

use App\Listener\ExceptionListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class ExceptionListenerTest extends TestCase
{
    public function testWithValidExceptionEvent(): void
    {
        // 1. 创建一个明确的异常实例,方便验证
        $testException = new \Exception('测试异常消息', 400);

        // 2. 构建ExceptionEvent对象
        $event = new ExceptionEvent(
            $this->createMock(HttpKernelInterface::class),
            $this->createMock(Request::class),
            HttpKernelInterface::MAIN_REQUEST, // 用常量更清晰
            $testException
        );

        // 3. 实例化监听器并触发__invoke方法
        $listener = new ExceptionListener();
        $listener($event);

        // 4. 验证Event的响应是否符合预期
        $response = $event->getResponse();
        $this->assertInstanceOf(JsonResponse::class, $response);

        // 解码JSON响应内容
        $responseData = json_decode($response->getContent(), true);
        $this->assertEquals('测试异常消息', $responseData['message']);
        $this->assertEquals(400, $responseData['code']);

        // 可选:验证响应状态码(默认是200,若需要可在监听器里修改)
        $this->assertEquals(200, $response->getStatusCode());
    }
}

关键验证点说明

  • 断言响应是JsonResponse类型,确保监听器设置了正确的响应格式
  • 解码响应内容后,验证message和code与异常的属性一致
  • 可选验证响应状态码,若你的业务需要特定状态码(比如400),可以在监听器里用new JsonResponse(..., 400),然后测试里断言对应状态码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:52:06