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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 09:36:05