【问题标题】:Doctrine Unit Test created_at field failure学说单元测试 created_at 字段失败
【发布时间】:2019-12-11 20:56:37
【问题描述】:

我正在使用带有学说 ORM 的 symfony3 我正在测试一个控制器动作,但断言失败,因为 created at 不同

public function testGetOneJobFound()
{
    $expected = '{"id":"a961c741-1c32-11ea-bfc6-0242ac130003","service_id":804040,"zipcode_id":"10115","title":"title","description":"decription","date_to_be_done":"2018-11-11T00:00:00+00:00","created_at":"2019-12-11T14:55:48+00:00"}';

    $this->client->request('GET', '/job/a961c741-1c32-11ea-bfc6-0242ac130003');

    $this->assertEquals(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
    $this->assertEquals($expected, $this->client->getResponse()->getContent());
}

单元测试结果: 时间:4.49 秒,内存:22.00MB

有 1 次失败:

1) Tests\AppBundle\Controller\JobControllerTest::testGetOneJobFound
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'{"id":"a961c741-1c32-11ea-bfc6-0242ac130003","service_id":804040,"zipcode_id":"10115","title":"title","description":"decription","date_to_be_done":"2018-11-11T00:00:00+00:00","created_at":"2019-12-11T14:55:48+00:00"}'
+'{"id":"a961c741-1c32-11ea-bfc6-0242ac130003","service_id":804040,"zipcode_id":"10115","title":"title","description":"decription","date_to_be_done":"2018-11-11T00:00:00+00:00","created_at":"2019-12-11T20:43:36+00:00"}'

如您所见,除了 created at 部分之外,响应看起来相同。

如何忽略响应中的 created_at。

【问题讨论】:

  • 一种选择是转换为数组,取消设置 created_at 并进行比较。
  • @FelippeDuarte 我虽然有同样的想法,但我不确定这是否是最佳做法

标签: php unit-testing symfony doctrine-orm


【解决方案1】:

一种常见的方法是json_decode() 内容,然后仅比较您感兴趣的数据,例如id, service_id, zipcode_id, ...

如果您想实际进行时间敏感测试,例如检查工作何时完成,您可以使用 Symfony 的 PHPUnitBridge 之类的东西来“冻结”时间,使用 Clock Mocking。这不适合您的 WebTestCase 和更多的单元测试。如果您想检查 created_at-timestamp,这大概是它的样子:

class Job
{
    public function __construct()
    {
        $this->createdAt = DateTime::createFromFormat('U', time());
    }

    public function getCreatedAt(): DateTime
    {
        return $this->createdAt;
    }
}

---

/**
 * @group time-sensitive
 */
public function testJobCreatedAtIsSetToCurrentTime(): void
{
    $job = new Job();

    $this->assertSame(time(), $job->getCreatedAt()->format('U'));
}

如果你想为你的 WebTestCase 提供类似的东西,或者你想测试更复杂的场景,只有某些时间被“冻结”,我能想到的最好的方法是不要使用 DateTime/DateTimeImmutable, @ 987654327@ 等,而是有一个时钟服务,它被注入到提供时间的服务中。这需要一些额外的工作和复杂性,但会使基于时间的测试更加可靠。拥有提供时间的服务可以将其替换为“FrozenClock”以进行测试。您可以使用一个库:lcobucci/clock,但您可以轻松编写更适合您需求的内容。如果我改用这个库,这就是之前的测试的样子:

class Job
{
    public function __construct(Clock $clock)
    {
        $this->createdAt = $clock->now();
    }

    public function getCreatedAt(): DateTimeImmutable
    {
        return $this->createdAt;
    }
}

---

public function testJobCreatedAtIsSetToCurrentTime(): void
{
    $clock = new FrozenClock(new DateTimeImmutable('2019-12-11T14:55:48+00:00'));
    $job = new Job();

    $this->assertSame('2019-12-11T14:55:48+00:00', $job->getCreatedAt()->format(DateTime::ATOM));
}

对于test/services.yaml 中的 Web 测试用例,您可以将别名为 Clock-interface 的任何服务更改为具有固定时间的 FrozenClock-service,以确保每个需要时钟的服务都使用该时间。

【讨论】:

    猜你喜欢
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多