Symfony5测试中如何模拟带ID的User实体对象?
问题描述
我有一个PurchaceFactory类,它的参数之一是User实体对象。我想要创建一个User对象用于测试,代码如下:
class PurchaceFactoryTest extends TestCase { public function testCreate() { $user = new User(); $user->setEmail('user1@email.com'); $user->setPassword('password'); $user->setRoles(["ROLE_USER", "ROLE_BUY"]); $jsonEncoder = new JsonEncoder(); $artworkData = [ "ID" => 129884, "title" => "Starry Night and the Astronauts", "author" => "Alma Thomas", "thumbnail" => [ "lqip" => "data:image/gif;base64,somebase64data", "width" => 800, "height" => 600, "alt_text" => "Al text" ] ]; $purchaceFactory = new PurchaceFactory($jsonEncoder); $purchace = $purchaceFactory->create($user, $artworkData); // 断言逻辑 //... } }
问题在于,通过bin/console make:user生成的User实体没有setId方法,无法设置id,但PurchaceFactory需要使用User的id属性。我不想修改User实体添加setId方法,因为id应该是不可变的,请问如何模拟一个带id的User对象?
解决方案
方案1:用PHPUnit反射直接修改私有/受保护的id属性
利用PHP的反射机制,无需修改User实体代码,就能直接访问并设置其私有/受保护的id属性:
public function testCreate() { $user = new User(); $user->setEmail('user1@email.com'); $user->setPassword('password'); $user->setRoles(["ROLE_USER", "ROLE_BUY"]); // 反射设置id $reflection = new \ReflectionClass($user); $idProperty = $reflection->getProperty('id'); $idProperty->setAccessible(true); $idProperty->setValue($user, 1); // 填入测试需要的id值 // 后续测试代码不变 $jsonEncoder = new JsonEncoder(); $artworkData = [/*...*/]; $purchaceFactory = new PurchaceFactory($jsonEncoder); $purchace = $purchaceFactory->create($user, $artworkData); // 断言逻辑 }
方案2:创建测试专用的User子类
如果User类不是final修饰的,可以在测试文件里定义一个子类,临时添加setId方法:
// 测试文件内定义子类 class TestUser extends User { public function setId(int $id): void { $this->id = $id; } } // 测试方法中使用 public function testCreate() { $user = new TestUser(); $user->setEmail('user1@email.com'); $user->setPassword('password'); $user->setRoles(["ROLE_USER", "ROLE_BUY"]); $user->setId(1); // 用子类方法设置id // 后续测试代码不变 }
方案3:Mock User接口(如果User实现了接口)
如果User实体实现了UserInterface这类包含getId()方法的接口,直接用PHPUnit的MockBuilder生成模拟对象:
public function testCreate() { // 创建User接口的Mock对象 $user = $this->createMock(UserInterface::class); $user->method('getId')->willReturn(1); $user->method('getEmail')->willReturn('user1@email.com'); // 根据PurchaceFactory依赖的User方法,补充对应的模拟返回逻辑 // 后续测试代码不变 $jsonEncoder = new JsonEncoder(); $artworkData = [/*...*/]; $purchaceFactory = new PurchaceFactory($jsonEncoder); $purchace = $purchaceFactory->create($user, $artworkData); // 断言逻辑 }
方案4:集成测试中用EntityManager生成id
如果是集成测试场景,可以借助Doctrine的EntityManager将User持久化到测试数据库,自动生成id后再使用:
public function testCreate() { $user = new User(); $user->setEmail('user1@email.com'); $user->setPassword('password'); $user->setRoles(["ROLE_USER", "ROLE_BUY"]); // 持久化到测试数据库,自动生成id $entityManager = $this->getEntityManager(); $entityManager->persist($user); $entityManager->flush(); // 此时user已包含自动生成的id $userId = $user->getId(); // 后续测试代码不变 $jsonEncoder = new JsonEncoder(); $artworkData = [/*...*/]; $purchaceFactory = new PurchaceFactory($jsonEncoder); $purchace = $purchaceFactory->create($user, $artworkData); // 断言逻辑 }
内容的提问来源于stack exchange,提问作者vaso123
相关产品推荐
相关产品推荐

