我的本地计算机上有几个单元测试失败,因为日期时间值不同:
4) TestsAppBundleFormAssetStatusTypeTest::testValidForm with data set #0 (array('active'))
Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
'status' => 'active'
'type' => null
'amount' => null
- 'createdAt' => 2018-09-20T20:34:47.047520+0200
+ 'createdAt' => 2018-09-20T20:34:47.047870+0200
'updatedAt' => null
'contract' => null
'admin' => null
测试:
public function testValidForm($data)
{
$form = $this->factory->create(AssetStatusType::class);
$object = Entity::fromArray(new Asset(), $data);
$form->submit($data);
$this->assertTrue($form->isSynchronized());
$this->assertEquals($object, $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($data) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
这或多或少是从文档中复制的。
现在,createdAt
字段设置如下:
public function __construct()
{
if (empty($this->createdAt)) {
$this->createdAt = new DateTime();
}
}
我的主要观点是:这个测试正在通过我们的 Jenkins。它不会在多台开发人员计算机上本地运行。我的第一个冲动是检查 ini 时区设置。
我想知道这怎么可能。如果我做对了,预期是创建object
的时间,实际是提交表单的时间。因此,两个对象永远不能具有相同的createdAt
时间戳。除非precision
可能是超低的。
两台机器运行不同版本的 PHP。 PHP7.1(及更高版本(在创建 DateTime 对象时包含微秒,但在 PHP 5.x 和 7.0 上运行的代码不会。
有两种方法可以使用它:
- 不要比较确切的日期时间,而是使用
$datetimeObj->format('U');
将它们转换为秒。当一个测试在 1.99998 处创建,而下一次创建日期时间的调用在 2.0001 处时,您仍然会偶尔遇到测试失败,因此测试在转换为秒时仍然失败。 - 使用"时钟模拟"。使用一些有趣的PHP命名空间技巧,全局
time()
函数被覆盖(sleep()
也被覆盖(。您必须创建新的 DateTime 对象以确保它们实际使用新版本的 time(( 函数,但时钟会有效地停止 - 而 sleep(( 只是变成更像$time += $seconds;
的东西 - 这也意味着sleep(3600);
需要有效的零时间。
symfony/phpunit-bridge ClockMock.php 可以用作库,如果你不想在 PHPunit 配置中将其作为侦听器包含在内。