如何测试修改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
相关产品推荐
相关产品推荐

