Search code examples
phpunitsymfony4php-7.2

How to fake DateTime in a phpunit test?


ssI write a unittest using Symfony's KernelTestCase and have to test for a functionality, which happens only at a certain tie of the day (extra early or extra late).

So when I let my test run a noon of course nothing happens. How can I fake my system time to pretend that it has a different time and my test case is triggered.

I tried around with Symfony's ClockMock class but it does not work. https://symfony.com/doc/current/components/phpunit_bridge.html#clock-mocking

This is my test code:

use Symfony\Bridge\PhpUnit\ClockMock;
use \DateTime;

/**
 * testUserAchievedEarlyBirdTrophy
 * @group time-sensitive
 */
public function testUserAchievedEarlyBirdTrophy()
{
    ClockMock::withClockMock(strtotime('2018-11-05 01:00:00'));
    echo (new DateTime())->format('Y-m-d H:m:s');

    $user8Id = $this->user8->getId();
    $progressSaveRequest = new ProgressSaveRequest($user8Id, $this->content_1_1->getId());

    $this->progressService->saveProgress($progressSaveRequest);

    $this->assertTrue($this->loggerCreator->hasDebugThatContains(
        'Early Bird'
    ));
}

the echo give me today's date: 2019-02-01 16:02:06

I also had the feeling that ClockMock is rather used to skip time for e.g. testing caching instead of sleep().

What am I doing wrong?

The listener configuration is in place in my phpunit.xml Calling bin/simple-phpunit causes a lot of installation happening.

Can't I use the normal phpunit?

Are there any other options to fake the time of the day?


Solution

  • Following the link you included in your post, the first paragraph says:

    The ClockMock class provided by this bridge allows you to mock the PHP's built-in time functions time(), microtime(), sleep() and usleep(). Additionally the function date() is mocked so it uses the mocked time if no timestamp is specified. Other functions with an optional timestamp parameter that defaults to time() will still use the system time instead of the mocked time. (Emphasis added.)

    This means that your call of

    echo (new DateTime())->format('Y-m-d H:m:s');
    

    is expected to give the system time, not the mocked time.

    Change it to

    echo date('Y-m-d H:m:s');
    

    in order to match the requirements of ClockMock and get the mocked time.

    Note: I've never used ClockMock myself, but just looking at the documentation this should be a first step to see if this resolves your problem.