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

如何在PHPUnit 10及以上版本中配置ClockMock?

如何在PHPUnit 10+中正确使用Symfony ClockMock?

ClockMock是用于创建时间敏感测试的工具,比如根据日期是过去还是未来执行不同逻辑。它属于symfony/phpunit-bridge组件,在PHPUnit 8中可正常使用,而symfony/phpunit-bridge 7.2版本已支持PHPUnit 10+。

项目配置

  • symfony: 6.4
  • php: 8.2
  • phpunit/phpunit: 10.5.41
  • symfony/phpunit-bridge: 7.2.0

遇到的问题

官方文档曾要求在phpunit.xml中配置SymfonyTestsListener监听器,但PHPUnit 10+已不再支持<listeners>配置项,移除监听器后,测试代码无法使用指定的模拟时间,始终调用系统当前时间。

原测试代码:

class CompanyNameHelperTest extends TestCase
{
    public function testGetCompanyNameByIdPast(): void
    {
        ClockMock::register(CompanyNameHelper::class);
        ClockMock::withClockMock(true);
        ClockMock::withClockMock(strtotime('2018-11-05 01:00:00'));
        $myDate = (new DateTimeImmutable(date('Y-m-d H:m:s')));
        $companyId = 1;
        $this->assertEquals(
            'ACME KG, Hamburg',
            CompanyNameHelper::getCompanyNameById($companyId, $myDate)
        );
        ClockMock::withClockMock(false);
    }
}

正确使用方式

1. 替换监听器为PHPUnit扩展配置

在phpunit.xml中,将原<listeners>配置替换为<extensions>:

<extensions>
    <extension class="Symfony\Bridge\PhpUnit\SymfonyTestsExtension"/>
</extensions>

这是PHPUnit 10+支持的扩展加载方式,替代了旧的监听器机制。

2. 修正测试代码的ClockMock调用

  • 移除多余的ClockMock::withClockMock(true);调用,直接使用setTime()设置模拟时间
  • 无需通过date()函数构造DateTime,直接实例化DateTimeImmutable即可(ClockMock会拦截时间相关的系统调用)
  • 使用ClockMock::reset()替代withClockMock(false)来重置时间模拟

修正后的测试代码:

class CompanyNameHelperTest extends TestCase
{
    public function testGetCompanyNameByIdPast(): void
    {
        // 注册需要拦截时间调用的目标类
        ClockMock::register(CompanyNameHelper::class);
        // 设置模拟的时间戳
        ClockMock::setTime(strtotime('2018-11-05 01:00:00'));

        // 直接实例化DateTime,会使用模拟的时间
        $myDate = new DateTimeImmutable();
        $companyId = 1;

        $this->assertEquals(
            'ACME KG, Hamburg',
            CompanyNameHelper::getCompanyNameById($companyId, $myDate)
        );

        // 重置时间模拟,恢复系统时间
        ClockMock::reset();
    }
}

3. 确保被测试类的时间调用被拦截

被测试的CompanyNameHelper类中,所有时间相关的操作(如date()、time()、new DateTime()等)必须是直接调用的,不能通过未注册的类或命名空间间接调用,否则ClockMock无法拦截这些调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:33:16