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

如何用PHPUnit测试Symfony命令的数据更新功能?

如何测试Symfony命令的数据更新操作

我正尝试编写一个测试类,用于测试Symfony命令执行时的数据更新操作,但不清楚如何编写功能测试。我需要了解在UpdateTrackedContainerCommandTest类中应编写哪些函数来验证数据已更新。在Symfony官方文档中未找到相关示例,希望能得到相关指导。

用于更新数据的Symfony命令类

#[AsCommand(
    name: 'app:update-data',
    description: 'Updating data',
    hidden: false
)]
class UpdateDataCommand extends Command
{
    private $repository;
    private $apiService;
    private $dbManager;

    public function __construct(
        Repository $repository,
        ApiService $apiService,
        DbManager $dbManager
    ) {
        $this->repository = $repository;
        $this->apiService = $apiService;
        $this->dbManager = $dbManager;

        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->setHelp('This command allows you to update data...')
            ->setDescription('Updating data');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $repositoryData = $this->repository->findAll();
        $isUpdatedData = false;

        foreach ($repositoryData as $dataRow) {
            $apiData = $this->apiService->getApiData($dataRow->getReference())['result'] ?? null;

            if ($apiData) {
                foreach ($apiData['result'] as $key => $row) {
                    if ($row['id'] == $dataRow['id']) {
                        $dataRow[$key] = $row[$key];
                        $this->dbManager->persist($dataRow);
                        $isUpdatedData = true;
                    }
                }
            }
        }

        if ($isUpdatedData) {
            $this->dbManager->flush();
        }

        return Command::SUCCESS;
    }
}

现有测试类

class UpdateTrackedContainerCommandTest extends KernelTestCase
{
    public function testExecute(): CommandTester
    {
        $kernel = self::bootKernel();
        $application = new Application($kernel);

        $command = $application->find('app:update-tracked-container');
        $commandTester = new CommandTester($command);
        $commandTester->execute([]);

        $commandTester->assertCommandIsSuccessful();

        return $commandTester;
    }
}

测试方案与示例代码

针对你的需求,需要补充以下核心测试逻辑,覆盖数据更新的关键场景:

1. 测试数据成功更新

验证当API返回有效更新数据时,数据库中的记录确实被修改:

public function testDataIsUpdatedWhenApiReturnsNewData(): void
{
    self::bootKernel();
    $container = self::getContainer();

    // 1. 准备测试数据:插入一条初始记录到数据库
    $testData = new YourDataEntity();
    $testData->setId(1);
    $testData->setReference('TEST_REF');
    $testData->setSomeField('old_value'); // 替换为你实际需要更新的字段

    $entityManager = $container->get(EntityManagerInterface::class);
    $entityManager->persist($testData);
    $entityManager->flush();
    $entityManager->clear(); // 清除缓存,确保后续查询从数据库读取

    // 2. 模拟ApiService的返回值
    $mockApiService = $this->createMock(ApiService::class);
    $mockApiService->method('getApiData')
        ->with('TEST_REF')
        ->willReturn([
            'result' => [
                ['id' => 1, 'someField' => 'new_value']
            ]
        ]);

    // 替换容器中的ApiService为模拟对象
    $container->set(ApiService::class, $mockApiService);

    // 3. 执行命令
    $application = new Application(self::$kernel);
    $command = $application->find('app:update-data');
    $commandTester = new CommandTester($command);
    $commandTester->execute([]);

    // 4. 验证命令执行成功
    $commandTester->assertCommandIsSuccessful();

    // 5. 从数据库重新查询记录,验证字段已更新
    $updatedData = $entityManager->find(YourDataEntity::class, 1);
    $this->assertEquals('new_value', $updatedData->getSomeField());
}

2. 测试无更新时不执行flush

确保当没有数据需要更新时,不会调用数据库的flush操作:

public function testFlushIsNotCalledWhenNoDataNeedsUpdate(): void
{
    self::bootKernel();
    $container = self::getContainer();

    // 1. 准备测试数据
    $testData = new YourDataEntity();
    $testData->setId(1);
    $testData->setReference('TEST_REF');
    $testData->setSomeField('current_value');

    $entityManager = $container->get(EntityManagerInterface::class);
    $entityManager->persist($testData);
    $entityManager->flush();
    $entityManager->clear();

    // 2. 模拟ApiService返回无匹配数据
    $mockApiService = $this->createMock(ApiService::class);
    $mockApiService->method('getApiData')
        ->with('TEST_REF')
        ->willReturn(['result' => []]);

    $container->set(ApiService::class, $mockApiService);

    // 3. 模拟DbManager,验证flush是否被调用
    $mockDbManager = $this->createMock(DbManager::class);
    $mockDbManager->expects($this->never())->method('flush');
    $container->set(DbManager::class, $mockDbManager);

    // 4. 执行命令
    $application = new Application(self::$kernel);
    $command = $application->find('app:update-data');
    $commandTester = new CommandTester($command);
    $commandTester->execute([]);

    $commandTester->assertCommandIsSuccessful();
}

3. 测试无API数据时不更新

验证当API返回空结果时,数据不会被修改:

public function testDataRemainsUnchangedWhenApiReturnsNull(): void
{
    self::bootKernel();
    $container = self::getContainer();

    // 1. 准备测试数据
    $testData = new YourDataEntity();
    $testData->setId(1);
    $testData->setReference('TEST_REF');
    $testData->setSomeField('original_value');

    $entityManager = $container->get(EntityManagerInterface::class);
    $entityManager->persist($testData);
    $entityManager->flush();
    $entityManager->clear();

    // 2. 模拟ApiService返回null
    $mockApiService = $this->createMock(ApiService::class);
    $mockApiService->method('getApiData')
        ->with('TEST_REF')
        ->willReturn(null);

    $container->set(ApiService::class, $mockApiService);

    // 3. 执行命令
    $application = new Application(self::$kernel);
    $command = $application->find('app:update-data');
    $commandTester = new CommandTester($command);
    $commandTester->execute([]);

    // 4. 验证数据未被修改
    $unchangedData = $entityManager->find(YourDataEntity::class, 1);
    $this->assertEquals('original_value', $unchangedData->getSomeField());
}

注意事项

  • 替换代码中的YourDataEntity为你实际使用的实体类
  • 测试前确保数据库处于干净状态,可使用PHPUnit的setUp/tearDown方法清理数据
  • 如果使用Doctrine,可利用SchemaTool在测试前重建数据库表,避免数据污染

内容的提问来源于stack exchange,提问作者Andrej Kozlovský

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 07:35:17