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

Symfony Doctrine在PHPUnit测试中异常:eup字段存入数据库为空

问题:Symfony测试环境下Doctrine未生成eup字段的INSERT语句

技术栈

  • Symfony v6.4.8
  • doctrine/orm 2.19.5
  • phpunit/phpunit 9.6.19

场景描述

在Symfony中构建了REST API GET端点/api/contract/{$id},该端点会请求外部系统API获取数据,结合本地数据库数据后,在本地MSSQL数据库创建新记录。其中eup字段在数据库中定义为nvarchar(10)类型。

核心保存代码

private function saveContract(EntityManager $em, array $data): ContractData
{        
    $contract = new ContractData();
    // [... 其他变量赋值]
    $contract->setEup($data['eup']);  // 示例值: "2024-06-29"
    
    $em->persist($contract);
    $em->flush();

    return $contract;
}

PHPUnit测试代码

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class ContractDataControllerTest extends WebTestCase
{
    public static function contractProvider(): array
    {
        $testCases = array(
            ['18fac35b-4afe-476e-9094-1437deeb6f0a', 'stringValue1', '2024-06-29'],
        );
        return $testCases;
    }
    
    /**
     * @covers \App\Controller\API\ContractDataController::contract
     * @dataProvider contractProvider
     */
    public function testGetContractWhileLoggedIn($id, $expectValue1, $expectEup): void
    {
        $uri = $this->getUriWithSignature('/api/contract/', $id);

        $client = static::createClient();
        $client->disableReboot();
        $client->setServerParameter('HTTP_Authorization', 'Bearer ' . $_ENV['TOKEN']);
        $client->request('GET', $uri);

        $this->assertResponseStatusCodeSame(200);

        $responseData = json_decode($client->getResponse()->getContent(), true);

        $this->assertSame($expectValue1, $responseData['value1']);
        // 其他字段测试正常,仅eup字段在数据库中为空
        $this->assertSame($expectEup, $responseData['valueEup']); 
    }
}

问题现象

  • Postman调用API时,记录能正确创建,eup字段会被填入预期字符串;
  • 运行PHPUnit测试php bin/phpunit --filter myTest时,记录能创建,但eup字段为NULL。

已做排查

  • 测试中其他字段均能正确存储;
  • 该字段的值可写入其他字段,排除值本身的格式/长度问题;
  • Xdebug确认:执行$em->persist($contract);时$contract->eup已被正确赋值为字符串,但flush()后数据库中该字段为NULL;
  • 添加Doctrine日志后发现,测试环境生成的SQL INSERT语句缺失eup字段:
    Executing statement: INSERT INTO contract_data (contract_number) VALUES (?) (parameters: array{"1":"XYZ123456"}, types: array{"1":2})
    

可能的原因及解决方向

  1. Doctrine元数据缓存未更新
    测试环境可能缓存了旧的实体元数据,导致新添加的eup字段未被识别。执行以下命令清除测试环境缓存:

    php bin/console cache:clear --env=test
    

    也可以在phpunit配置中禁用元数据缓存,确保每次测试都读取最新的实体映射。

  2. 实体映射配置不一致
    检查ContractData实体的映射(注释/XML/YAML文件),确认测试环境下的映射是否包含eup字段。有可能测试环境使用了独立的映射配置文件,或者映射定义中遗漏了该字段,导致Doctrine生成SQL时忽略它。

  3. 测试环境数据库Schema未同步
    测试环境的数据库表结构可能未同步最新的变更,比如eup字段是新增的,但测试库中还没有该字段,或者字段配置与生产环境不一致。可以运行以下命令同步测试库Schema:

    php bin/console doctrine:schema:update --force --env=test
    
  4. 测试环境的外部API Mock数据异常
    测试时如果Mock了外部系统API的响应,需要确认Mock返回的数据中包含正确的eup值。虽然Xdebug看到$contract->eup已赋值,但要验证这个值确实来自外部API的Mock响应,而非测试代码中的硬编码遗漏。

  5. 实体Setter方法隐藏逻辑
    虽然Postman调用正常,但要再次确认setEup方法没有特殊逻辑(比如条件赋值、数据转换错误),且测试环境下的实体类代码与生产环境一致,不存在分支代码差异导致值被清空的情况。

内容的提问来源于stack exchange,提问作者SvenW

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:37:35