Skip to content
Simple Analytics

Testing Aids ​

When writing unit tests, it is helpful to fixate the current time. Chronos provides several methods to mock the current time for testing.

Setting Test Time ​

You can fix the current time using setTestNow():

php
use Cake\Chronos\Chronos;
use Cake\Chronos\ChronosDate;

// Fix the current time
Chronos::setTestNow(new Chronos('2015-12-25 00:00:00'));

// Now all "now" calls return the fixed time
$time = Chronos::now();        // 2015-12-25 00:00:00
$time = new Chronos();         // 2015-12-25 00:00:00
$time = new Chronos('1 hour ago'); // 2015-12-24 23:00:00

Relative expressions are calculated from the test time:

php
Chronos::setTestNow(new Chronos('2015-12-25 00:00:00'));

$time = new Chronos('+2 days');  // 2015-12-27 00:00:00
$time = Chronos::parse('yesterday'); // 2015-12-24 00:00:00

Resetting Test Time ​

To reset the fixation, call setTestNow() with no parameter or null:

php
Chronos::setTestNow();
// or
Chronos::setTestNow(null);

Checking Test Mode ​

You can check if test time is currently set:

php
if (Chronos::hasTestNow()) {
    // Currently in test mode
}

// Get the current test time (null if not set)
$testTime = Chronos::getTestNow();

Scoped Test Time ​

For cleaner tests, you can use withTestNow() which automatically resets the test time after your callback completes:

php
$result = Chronos::withTestNow('2015-12-25 10:00:00', function () {
    // Inside this callback, "now" is fixed to 2015-12-25 10:00:00
    $time = Chronos::now();

    // Do your assertions...
    return $time->hour; // 10
});

// After the callback, test time is automatically reset
// $result contains the return value from the callback

This is especially useful in test methods:

php
public function testChristmasDiscount(): void
{
    Chronos::withTestNow('2015-12-25', function () {
        $order = new Order();
        $this->assertTrue($order->hasChristmasDiscount());
    });

    Chronos::withTestNow('2015-07-04', function () {
        $order = new Order();
        $this->assertFalse($order->hasChristmasDiscount());
    });
}

The callback can also accept the test time as a parameter:

php
Chronos::withTestNow('2015-12-25', function (Chronos $now) {
    echo $now->format('Y-m-d'); // 2015-12-25
});

ChronosDate Test Time ​

ChronosDate has its own separate test time:

php
use Cake\Chronos\ChronosDate;

ChronosDate::setTestNow(ChronosDate::parse('2015-12-25'));

$today = ChronosDate::today(); // 2015-12-25

// Reset
ChronosDate::setTestNow();

Test Suite Setup ​

In your test suite's bootstrap process, you might want to set a fixed time for all tests:

php
// In tests/bootstrap.php
Chronos::setTestNow(Chronos::now());
ChronosDate::setTestNow(ChronosDate::today());

Or use the scoped version in individual test methods or setUp/tearDown:

php
protected function setUp(): void
{
    parent::setUp();
    Chronos::setTestNow('2015-12-25 12:00:00');
}

protected function tearDown(): void
{
    Chronos::setTestNow();
    parent::tearDown();
}

Released under the MIT License.