PHPUnit表单测试在DateTime上失败

时间:2018-09-20 18:59:48

标签: symfony phpunit

由于DateTime值不同,我的本地计算机上有多个单元测试失败:

4) Tests\AppBundle\Form\AssetStatusTypeTest::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);
    }
}

或多或少copied from the docs

现在,createdAt字段的设置如下:

public function __construct()
{
    if (empty($this->createdAt)) {
        $this->createdAt = new \DateTime();
    }
}

我的主要观点是:该测试正在通过我们的詹金斯大学。它不在本地几台开发人员计算机上。我的第一个冲动是检查ini时区设置。

我想知道这怎么可能。如果我做对了,应该是创建object的时间,而实际是提交表单的时间。因此,两个对象永远不能具有相同的createdAt时间戳。除非precision可能超低。

1 个答案:

答案 0 :(得分:2)

两台机器正在运行不同版本的PHP。 PHP7.1(及更高版本)在创建DateTime对象时包含微秒,但在PHP 5.x和7.0上运行的代码不会。

有两种处理方法:

  • 不比较确切的日期时间,而是使用$datetimeObj->format('U');将它们转换为秒。当在1.99998上创建一个测试,而在下一个创建日期时间的调用在2.0001上创建时,您仍然会偶尔遇到测试失败,因此转换为秒后该测试仍然会失败。
  • 使用“ Clock Mocking”。使用一些有趣的PHP名称空间技巧,将覆盖全局time()函数(也sleep())。您必须创建一个新的DateTime对象,以确保它们实际上使用了新版本的time()函数,但是时钟实际上会停止-并且sleep()变成了更像$time += $seconds;的东西-这也表示sleep(3600);需要有效的零时间。

如果您不想在PHPunit配置中将symfony / phpunit-bridge ClockMock.php用作侦听器,则可以将其用作库。