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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:52:38