Symfony项目postPersist自定义监听器单元测试Mock报错如何解决
Symfony postPersist事件监听器单元测试方案
现有测试问题梳理
- 报错直接原因:
getEntityManager()是LifecycleEventArgs类的方法,你尝试给EntityManagerInterface的Mock配置不存在的方法,触发报错 - 构造监听器时漏传第二个必填参数
EntityManagerInterface实例 - 调用
handle()方法时第一个参数传错,应该传入LifecycleEventArgs实例而非监听器本身 - 未设置
LifecycleEventArgs返回MyEntity实例的桩逻辑,也没有验证持久化相关方法的调用,没有覆盖核心验证目标 - 未对
UnitOfWork的getEntityChangeSet方法做正确的桩配置
修正后测试代码
use PHPUnit\Framework\TestCase; use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\EntityManagerInterface; class MyCustomListenerTest extends TestCase { public function testPostPersistWillPersistActionRecordWhenEntityIsMyEntity() { // 1. 准备依赖Mock $mockEntityService = $this->createMock(MyEntityService::class); $mockEm = $this->createMock(EntityManagerInterface::class); $mockUow = $this->createMock(UnitOfWork::class); $mockArgs = $this->createMock(LifecycleEventArgs::class); // 2. 配置桩逻辑 $testMyEntity = new MyEntity(); // 配置LifecycleEventArgs返回MyEntity实例和对应的EntityManager $mockArgs->method('getObject')->willReturn($testMyEntity); $mockArgs->method('getEntityManager')->willReturn($mockEm); // 配置EntityManager返回UnitOfWork $mockEm->method('getUnitOfWork')->willReturn($mockUow); // 配置UnitOfWork返回变更集(原代码未使用该值,随便返回空数组即可) $mockUow->method('getEntityChangeSet')->willReturn([]); // 3. 验证持久化方法被正确调用 $mockEm->expects($this->once()) ->method('persist') ->with($this->callback(function($newEntity) use ($testMyEntity) { // 验证新创建的实体属性符合预期 return $newEntity instanceof MyEntity && $newEntity->getEntityId() === $testMyEntity && $newEntity->getTypeOfAction() === MyCustomListener::CREATED; })); $mockEm->expects($this->once())->method('flush'); // 4. 执行测试逻辑 $listener = new MyCustomListener($mockEntityService, $mockEm); $listener->postPersist($mockArgs); } // 补充反面测试:非MyEntity实例不会触发持久化 public function testPostPersistWillDoNothingWhenEntityIsNotMyEntity() { $mockEntityService = $this->createMock(MyEntityService::class); $mockEm = $this->createMock(EntityManagerInterface::class); $mockArgs = $this->createMock(LifecycleEventArgs::class); $mockArgs->method('getObject')->willReturn(new \stdClass()); // 非MyEntity实例 // 验证persist和flush都不会被调用 $mockEm->expects($this->never())->method('persist'); $mockEm->expects($this->never())->method('flush'); $listener = new MyCustomListener($mockEntityService, $mockEm); $listener->postPersist($mockArgs); } }
额外优化建议
你的监听器handle方法中已经通过$args->getEntityManager()获取了事件对应的实体管理器,但后续持久化用的是构造注入的$this->em,如果你的项目存在多实体管理器的场景,建议统一使用事件里获取的实体管理器,避免跨管理器操作的问题。
内容的提问来源于stack exchange,提问作者cervico
相关产品推荐
相关产品推荐

