Symfony5.3+PHPUnit8.5测试Mock Repository出现MappingException/TypeError问题
1. MappingException 触发原因
你用createStub模拟STypeRepository时,PHPUnit会生成一个继承自STypeRepository的随机类(也就是报错里的Mock_SType_b1b7aee4)。如果你的业务代码中调用了STypeRepository没有重写的父类方法(比如find、findBy等原生Repository方法),就会触发Doctrine的元数据读取逻辑,Doctrine会去检查当前Repository对应的实体类是否在配置的命名空间下,而PHPUnit生成的模拟类不在App\Entity命名空间下,因此抛出映射异常。
其他Repository模拟正常,是因为你给这些Repository被调用的方法都做了显式打桩,逻辑不会走到Doctrine底层的元数据读取流程。
2. TypeError 触发原因
getRepository默认返回通用的Doctrine\ORM\EntityRepository实例,只有当你在SType实体类的映射配置中声明了自定义Repository类,Doctrine才会返回你写的App\Repository\STypeRepository实例。你没有给SType配置关联的自定义Repository,所以拿到的实例和UserManager构造函数要求的类型不匹配,抛出类型错误。
方案1:继续使用模拟Repository
给STypeRepository所有会被本次测试逻辑调用的方法做显式打桩,避免逻辑走到父类EntityRepository的原生方法即可。示例:
$sTypeRepository = $this->createStub(STypeRepository::class); // 假设UserManager会调用findByActive方法,显式定义桩方法返回值 $sTypeRepository->method('findByActive') ->willReturn([]);
如果后续有大量类似场景,建议给自定义Repository提取独立接口,业务类依赖接口而非具体Repository类,模拟接口时不会出现父类继承带来的底层逻辑调用问题。
方案2:使用真实Repository实例
在SType实体的映射配置中声明关联的自定义Repository:
- 注解/属性方式(PHP7+/PHP8):
// src/Entity/SType.php use Doctrine\ORM\Mapping as ORM; use App\Repository\STypeRepository; /** * @ORM\Entity(repositoryClass=STypeRepository::class) */ class SType { // 实体字段定义 }
如果用XML/YAML做映射,在对应的映射文件中配置repositoryClass参数即可。配置完成后清理测试环境缓存,再调用getRepository(SType::class)就会返回符合类型要求的自定义Repository实例。
内容的提问来源于stack exchange,提问作者michaelf

