Skip to content

Commit

Permalink
Replace Chronos with PSR-20 Clock interface
Browse files Browse the repository at this point in the history
  • Loading branch information
odan committed Nov 16, 2023
1 parent c822a03 commit fc8af3a
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ This project is based on best practices and industry standards:
* Autoloader (PSR-4)
* Logger (PSR-3)
* Code styles (PSR-12)
* Clock interoperability (PSR-20)
* Single action controllers
* Input validation
* Query Builder
* Immutable date time ([Chronos](https://github.com/cakephp/chronos))
* Unit- and integration tests
* Console Commands
* Tested with [Github Actions](https://github.com/odan/slim4-skeleton/actions) and [Scrutinizer CI](https://scrutinizer-ci.com/)
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@
"php": "^8.1",
"ext-json": "*",
"ext-pdo": "*",
"cakephp/chronos": "^3",
"cakephp/database": "^5",
"cakephp/validation": "^5",
"fig/http-message-util": "^1.1",
"monolog/monolog": "^3",
"nyholm/psr7": "^1.4",
"nyholm/psr7-server": "^1.0",
"nyholm/psr7": "^1.8.1",
"nyholm/psr7-server": "^1.1",
"php-di/php-di": "^7",
"psr/clock": "^1.0",
"selective/basepath": "^2",
"slim/slim": "^4"
"slim/slim": "^4",
"symfony/clock": "^6.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3",
Expand Down
6 changes: 6 additions & 0 deletions config/container.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Nyholm\Psr7\Factory\Psr17Factory;
use Psr\Clock\ClockInterface;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
Expand All @@ -18,6 +19,7 @@
use Slim\Factory\AppFactory;
use Slim\Interfaces\RouteParserInterface;
use Slim\Middleware\ErrorMiddleware;
use Symfony\Component\Clock\NativeClock;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputOption;

Expand Down Expand Up @@ -128,4 +130,8 @@

return $application;
},

ClockInterface::class => function () {
return new NativeClock();
},
];
48 changes: 22 additions & 26 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,42 +199,38 @@ $password = $this->getTableRowById('users', 1)['password'];
## Testing with Date and Time

To change the date and time for testing purposes, invoke the
`Chronos::setTestNow` method within a test as follows:
`setTestNow` method within a test as follows:

```php
use Cake\Chronos\Chronos;

Chronos::setTestNow('2022-02-01 00:00:00');
$thia->setTestNow('2024-01-01 00:00:00');
```

## Mocking
To get the current date and time within the application,
declare the `Psr\Clock\ClockInterface $clock` as class dependency
and invoke the `now()` method.

When testing Slim applications, you may wish to "mock" certain aspects of your
application, so they are not actually executed during a test.
For example, when testing a service that needs a repository,
you may wish to mock the repository so that it's not actually
executed queries during the test.
**Example**

Note: Mocking is not a good testing method, because you may
not test the code you actually deploy, and furthermore,
if you change the code, you will have to change the test as well.
The meaningfulness and maintainability of tests with a
mock is thus significantly lower compared to a test
that tests the entire code.
````php
<?php

The `AppTestTrait` provides methods for mocking objects into the container.
namespace Example;

Mocking methods:
use Psr\Clock\ClockInterface;

```php
$this->mock(UserCreator::class)->method('createUser')->willReturn(1);
```
final class MyClass
{
public function __construct(private readonly ClockInterface $clock)
{
}

For better IDE support you may better use the `mockMethod` helper:

```php
$this->mockMethod([UserReaderRepository::class, 'getUserById'])
->willReturn(['example' => 'data']);
public function insertCustomer(array $customer): int
{
$now = $this->clock->now();

// ...
}
}
```

## Read more
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function findCustomers(): array
]
);

// Add more "use case specific" conditions to the query
// Add more conditions to the query
// ...

return $query->execute()->fetchAll('assoc') ?: [];
Expand Down
3 changes: 1 addition & 2 deletions tests/TestCase/Action/Customer/CustomerCreatorActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Test\TestCase\Action\Customer;

use App\Test\Traits\AppTestTrait;
use Cake\Chronos\Chronos;
use Fig\Http\Message\StatusCodeInterface;
use PHPUnit\Framework\TestCase;
use Selective\TestTrait\Traits\DatabaseTestTrait;
Expand All @@ -20,7 +19,7 @@ class CustomerCreatorActionTest extends TestCase

public function testCreateCustomer(): void
{
Chronos::setTestNow('2021-01-01 00:00:00');
$this->setTestNow('2021-02-01 00:00:00');

$request = $this->createJsonRequest(
'POST',
Expand Down
3 changes: 1 addition & 2 deletions tests/TestCase/Action/Customer/CustomerUpdaterActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use App\Test\Fixture\CustomerFixture;
use App\Test\Traits\AppTestTrait;
use Cake\Chronos\Chronos;
use Fig\Http\Message\StatusCodeInterface;
use PHPUnit\Framework\TestCase;
use Selective\TestTrait\Traits\DatabaseTestTrait;
Expand All @@ -21,7 +20,7 @@ class CustomerUpdaterActionTest extends TestCase

public function testUpdateCustomer(): void
{
Chronos::setTestNow('2021-02-01 00:00:00');
$this->setTestNow('2024-01-31 00:00:00');

$this->insertFixtures([CustomerFixture::class]);

Expand Down
1 change: 1 addition & 0 deletions tests/Traits/AppTestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
trait AppTestTrait
{
use ArrayTestTrait;
use ClockTestTrait;
use ContainerTestTrait;
use HttpTestTrait;
use HttpJsonTestTrait;
Expand Down
19 changes: 19 additions & 0 deletions tests/Traits/ClockTestTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Test\Traits;

use DateTimeImmutable;
use DateTimeZone;
use Psr\Clock\ClockInterface;
use Symfony\Component\Clock\MockClock;

/**
* PSR-20 Test Clock.
*/
trait ClockTestTrait
{
private function setTestNow(DateTimeImmutable|string $now = 'now', DateTimeZone|string $timezone = null): void
{
$this->container->set(ClockInterface::class, new MockClock($now, $timezone));
}
}

0 comments on commit fc8af3a

Please sign in to comment.