发布于2026-07-11 阅读(0)
扫一扫,手机访问
MockClock 必须通过 Symfony 的 ClockInterface 依赖注入机制生效,直接 new 无法影响业务逻辑;常见错误是测试中创建了 MockClock 但服务仍用默认 SystemClock,需确保被测类接收 ClockInterface 且容器正确覆盖该服务。

MockClock 能精准控制时间流逝,但必须配合 Symfony 的 ClockInterface 注入机制才能生效——直接 new MockClock 并不能影响业务逻辑中的时间判断。
这个坑很多人踩过:测试里吭哧吭哧创建了 MockClock,结果优惠判断纹丝不动。问题出在哪?业务代码仍然在调用系统时钟,而不是你模拟的那个。Symfony 的时间敏感组件(像 RateLimiter、自定义的优惠过期检查)默认依赖容器注入的 ClockInterface 实例,如果你没有显式替换它,MockClock 在测试中改的只是自己的局部时间,业务那边完全不受影响。
ClockInterface——而不是硬编码 new DateTimeImmutable()。这一步是前提。MockClock 实例正确传入了服务。比如用 new DiscountService($mockClock) 手动注入,而不是依赖容器自动解析。ClockInterface 的服务定义,让它指向你的 MockClock 实例。理解 MockClock 的核心机制很重要:它不是在时间轴上“跳转”,而是维护一个基准时间原点,然后通过 sleep() 和 advance() 方法偏移这个基准。所以想模拟时间流逝,得先设定起始点,再一步步往前推。
$mockClock = new MockClock(new DateTimeImmutable('2024-01-01 10:00:00')) 设定起始时刻。$mockClock->now() 拿到当前模拟时间,与优惠的 startsAt 字段比较。$mockClock->advance(7200)(单位是秒),再调 now() 就得到 2024-01-01 12:00:00。now() 刚好等于 expiresAt,再推进一次就过期了。时区是个容易翻车的细节。MockClock 默认使用 date_default_timezone_get() 的时区,如果你的优惠逻辑依赖 UTC 或某个特定时区(比如 Asia/Shanghai),而测试环境的时区设置不一致,那 now() 返回的时间戳就会跟预期对不上。
new DateTimeImmutable('2024-01-01 10:00:00', new DateTimeZone('UTC')) 来创建 MockClock。strtotime() 或模糊字符串(像 '+2 hours')来初始化——它依赖本地时区,而且毫秒级精度无法保证。sleep() 方法做真正的等待。它只是个语义化别名,底层还是 advance()。真正的“等待”应该由测试流程来控制,而不是让 CPU 真去睡一觉。最后强调一个最容易被忽略的点:MockClock 只改变它自身返回的时间,不会改写 PHP 全局的时间函数(比如 time() 或 date())。你所有的时间判断,必须老老实实地经过注入的 ClockInterface 实例去拿,否则模拟完全是空转。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8