Yii单元测试中时间戳异常主因是环境不一致,应禁用NOW()改用固定值,并验证相对逻辑而非绝对时间,统一PHP与MySQL时区为UTC。

时间戳字段在测试中为何总对不上
常见表现是:插入后查出的 created_at 和预期值差几秒、毫秒不一致,或测试用例在不同机器上结果不稳定。这是因为默认配置里用了 new Expression('NOW()') —— 它依赖 MySQL 服务端当前时间,而 PHPUnit 运行时无法控制数据库服务器的精确时刻,也难以 mock 数据库函数。
推荐做法:测试时禁用数据库时间函数
在单元测试配置中,把时间戳行为的 value 替换为固定时间或可预测值:
- 在测试专用模型类中重写
behaviors(),例如返回time()或strtotime('2026-08-17 12:00:00') - 或在测试 setUp() 中临时修改行为配置:
$model->attachBehavior('timestamp', [... 'value' => 1755432000]) - 避免在测试中依赖
Expression,它无法被 PHPUnit 拦截或断言
测试中正确验证时间戳字段
不要断言绝对时间值,而应验证相对逻辑是否成立:
- 新建模型未保存前,
$model->created_at应为 null(或 0,取决于字段类型) - 调用
save()后,$model->created_at和$model->updated_at均不为 null,且两者相等 - 再次
save()后,updated_at应大于初值,created_at不变 - 使用
assertEqualsWithDelta($expected, $actual, 2)允许 2 秒误差,避开精度干扰
时区与数据库一致性检查
测试失败常因 PHP 时区(date_default_timezone_set)和 MySQL 时区(SELECT @@time_zone)不一致:
- 确保测试数据库连接配置中显式设置时区,例如
'initSQLs' => ["SET time_zone = '+00:00'"] - PHP 测试脚本开头统一设为 UTC:
date_default_timezone_set('UTC') - 若字段是
DATETIME类型(无时区),就别用Carbon::now()->tz('Asia/Shanghai')去比对


















