Initial project structure with Slim skeleton
This commit is contained in:
78
tests/Application/Actions/ActionTest.php
Normal file
78
tests/Application/Actions/ActionTest.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Application\Actions;
|
||||
|
||||
use App\Application\Actions\Action;
|
||||
use App\Application\Actions\ActionPayload;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ActionTest extends TestCase
|
||||
{
|
||||
public function testActionSetsHttpCodeInRespond()
|
||||
{
|
||||
$app = $this->getAppInstance();
|
||||
$container = $app->getContainer();
|
||||
$logger = $container->get(LoggerInterface::class);
|
||||
|
||||
$testAction = new class($logger) extends Action {
|
||||
public function __construct(
|
||||
LoggerInterface $loggerInterface
|
||||
) {
|
||||
parent::__construct($loggerInterface);
|
||||
}
|
||||
|
||||
public function action(): Response
|
||||
{
|
||||
return $this->respond(
|
||||
new ActionPayload(
|
||||
202,
|
||||
[
|
||||
'willBeDoneAt' => (new DateTimeImmutable())->format(DateTimeImmutable::ATOM)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
$app->get('/test-action-response-code', $testAction);
|
||||
$request = $this->createRequest('GET', '/test-action-response-code');
|
||||
$response = $app->handle($request);
|
||||
|
||||
$this->assertEquals(202, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testActionSetsHttpCodeRespondData()
|
||||
{
|
||||
$app = $this->getAppInstance();
|
||||
$container = $app->getContainer();
|
||||
$logger = $container->get(LoggerInterface::class);
|
||||
|
||||
$testAction = new class($logger) extends Action {
|
||||
public function __construct(
|
||||
LoggerInterface $loggerInterface
|
||||
) {
|
||||
parent::__construct($loggerInterface);
|
||||
}
|
||||
|
||||
public function action(): Response
|
||||
{
|
||||
return $this->respondWithData(
|
||||
[
|
||||
'willBeDoneAt' => (new DateTimeImmutable())->format(DateTimeImmutable::ATOM)
|
||||
],
|
||||
202
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
$app->get('/test-action-response-code', $testAction);
|
||||
$request = $this->createRequest('GET', '/test-action-response-code');
|
||||
$response = $app->handle($request);
|
||||
|
||||
$this->assertEquals(202, $response->getStatusCode());
|
||||
}
|
||||
}
|
40
tests/Application/Actions/User/ListUserActionTest.php
Normal file
40
tests/Application/Actions/User/ListUserActionTest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Application\Actions\User;
|
||||
|
||||
use App\Application\Actions\ActionPayload;
|
||||
use App\Domain\User\UserRepository;
|
||||
use App\Domain\User\User;
|
||||
use DI\Container;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ListUserActionTest extends TestCase
|
||||
{
|
||||
public function testAction()
|
||||
{
|
||||
$app = $this->getAppInstance();
|
||||
|
||||
/** @var Container $container */
|
||||
$container = $app->getContainer();
|
||||
|
||||
$user = new User(1, 'bill.gates', 'Bill', 'Gates');
|
||||
|
||||
$userRepositoryProphecy = $this->prophesize(UserRepository::class);
|
||||
$userRepositoryProphecy
|
||||
->findAll()
|
||||
->willReturn([$user])
|
||||
->shouldBeCalledOnce();
|
||||
|
||||
$container->set(UserRepository::class, $userRepositoryProphecy->reveal());
|
||||
|
||||
$request = $this->createRequest('GET', '/users');
|
||||
$response = $app->handle($request);
|
||||
|
||||
$payload = (string) $response->getBody();
|
||||
$expectedPayload = new ActionPayload(200, [$user]);
|
||||
$serializedPayload = json_encode($expectedPayload, JSON_PRETTY_PRINT);
|
||||
|
||||
$this->assertEquals($serializedPayload, $payload);
|
||||
}
|
||||
}
|
79
tests/Application/Actions/User/ViewUserActionTest.php
Normal file
79
tests/Application/Actions/User/ViewUserActionTest.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Application\Actions\User;
|
||||
|
||||
use App\Application\Actions\ActionError;
|
||||
use App\Application\Actions\ActionPayload;
|
||||
use App\Application\Handlers\HttpErrorHandler;
|
||||
use App\Domain\User\User;
|
||||
use App\Domain\User\UserNotFoundException;
|
||||
use App\Domain\User\UserRepository;
|
||||
use DI\Container;
|
||||
use Slim\Middleware\ErrorMiddleware;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ViewUserActionTest extends TestCase
|
||||
{
|
||||
public function testAction()
|
||||
{
|
||||
$app = $this->getAppInstance();
|
||||
|
||||
/** @var Container $container */
|
||||
$container = $app->getContainer();
|
||||
|
||||
$user = new User(1, 'bill.gates', 'Bill', 'Gates');
|
||||
|
||||
$userRepositoryProphecy = $this->prophesize(UserRepository::class);
|
||||
$userRepositoryProphecy
|
||||
->findUserOfId(1)
|
||||
->willReturn($user)
|
||||
->shouldBeCalledOnce();
|
||||
|
||||
$container->set(UserRepository::class, $userRepositoryProphecy->reveal());
|
||||
|
||||
$request = $this->createRequest('GET', '/users/1');
|
||||
$response = $app->handle($request);
|
||||
|
||||
$payload = (string) $response->getBody();
|
||||
$expectedPayload = new ActionPayload(200, $user);
|
||||
$serializedPayload = json_encode($expectedPayload, JSON_PRETTY_PRINT);
|
||||
|
||||
$this->assertEquals($serializedPayload, $payload);
|
||||
}
|
||||
|
||||
public function testActionThrowsUserNotFoundException()
|
||||
{
|
||||
$app = $this->getAppInstance();
|
||||
|
||||
$callableResolver = $app->getCallableResolver();
|
||||
$responseFactory = $app->getResponseFactory();
|
||||
|
||||
$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory);
|
||||
$errorMiddleware = new ErrorMiddleware($callableResolver, $responseFactory, true, false, false);
|
||||
$errorMiddleware->setDefaultErrorHandler($errorHandler);
|
||||
|
||||
$app->add($errorMiddleware);
|
||||
|
||||
/** @var Container $container */
|
||||
$container = $app->getContainer();
|
||||
|
||||
$userRepositoryProphecy = $this->prophesize(UserRepository::class);
|
||||
$userRepositoryProphecy
|
||||
->findUserOfId(1)
|
||||
->willThrow(new UserNotFoundException())
|
||||
->shouldBeCalledOnce();
|
||||
|
||||
$container->set(UserRepository::class, $userRepositoryProphecy->reveal());
|
||||
|
||||
$request = $this->createRequest('GET', '/users/1');
|
||||
$response = $app->handle($request);
|
||||
|
||||
$payload = (string) $response->getBody();
|
||||
$expectedError = new ActionError(ActionError::RESOURCE_NOT_FOUND, 'The user you requested does not exist.');
|
||||
$expectedPayload = new ActionPayload(404, null, $expectedError);
|
||||
$serializedPayload = json_encode($expectedPayload, JSON_PRETTY_PRINT);
|
||||
|
||||
$this->assertEquals($serializedPayload, $payload);
|
||||
}
|
||||
}
|
59
tests/Domain/User/UserTest.php
Normal file
59
tests/Domain/User/UserTest.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Domain\User;
|
||||
|
||||
use App\Domain\User\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
public function userProvider()
|
||||
{
|
||||
return [
|
||||
[1, 'bill.gates', 'Bill', 'Gates'],
|
||||
[2, 'steve.jobs', 'Steve', 'Jobs'],
|
||||
[3, 'mark.zuckerberg', 'Mark', 'Zuckerberg'],
|
||||
[4, 'evan.spiegel', 'Evan', 'Spiegel'],
|
||||
[5, 'jack.dorsey', 'Jack', 'Dorsey'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider userProvider
|
||||
* @param int $id
|
||||
* @param string $username
|
||||
* @param string $firstName
|
||||
* @param string $lastName
|
||||
*/
|
||||
public function testGetters(int $id, string $username, string $firstName, string $lastName)
|
||||
{
|
||||
$user = new User($id, $username, $firstName, $lastName);
|
||||
|
||||
$this->assertEquals($id, $user->getId());
|
||||
$this->assertEquals($username, $user->getUsername());
|
||||
$this->assertEquals($firstName, $user->getFirstName());
|
||||
$this->assertEquals($lastName, $user->getLastName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider userProvider
|
||||
* @param int $id
|
||||
* @param string $username
|
||||
* @param string $firstName
|
||||
* @param string $lastName
|
||||
*/
|
||||
public function testJsonSerialize(int $id, string $username, string $firstName, string $lastName)
|
||||
{
|
||||
$user = new User($id, $username, $firstName, $lastName);
|
||||
|
||||
$expectedPayload = json_encode([
|
||||
'id' => $id,
|
||||
'username' => $username,
|
||||
'firstName' => $firstName,
|
||||
'lastName' => $lastName,
|
||||
]);
|
||||
|
||||
$this->assertEquals($expectedPayload, json_encode($user));
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Infrastructure\Persistence\User;
|
||||
|
||||
use App\Domain\User\User;
|
||||
use App\Domain\User\UserNotFoundException;
|
||||
use App\Infrastructure\Persistence\User\InMemoryUserRepository;
|
||||
use Tests\TestCase;
|
||||
|
||||
class InMemoryUserRepositoryTest extends TestCase
|
||||
{
|
||||
public function testFindAll()
|
||||
{
|
||||
$user = new User(1, 'bill.gates', 'Bill', 'Gates');
|
||||
|
||||
$userRepository = new InMemoryUserRepository([1 => $user]);
|
||||
|
||||
$this->assertEquals([$user], $userRepository->findAll());
|
||||
}
|
||||
|
||||
public function testFindAllUsersByDefault()
|
||||
{
|
||||
$users = [
|
||||
1 => new User(1, 'bill.gates', 'Bill', 'Gates'),
|
||||
2 => new User(2, 'steve.jobs', 'Steve', 'Jobs'),
|
||||
3 => new User(3, 'mark.zuckerberg', 'Mark', 'Zuckerberg'),
|
||||
4 => new User(4, 'evan.spiegel', 'Evan', 'Spiegel'),
|
||||
5 => new User(5, 'jack.dorsey', 'Jack', 'Dorsey'),
|
||||
];
|
||||
|
||||
$userRepository = new InMemoryUserRepository();
|
||||
|
||||
$this->assertEquals(array_values($users), $userRepository->findAll());
|
||||
}
|
||||
|
||||
public function testFindUserOfId()
|
||||
{
|
||||
$user = new User(1, 'bill.gates', 'Bill', 'Gates');
|
||||
|
||||
$userRepository = new InMemoryUserRepository([1 => $user]);
|
||||
|
||||
$this->assertEquals($user, $userRepository->findUserOfId(1));
|
||||
}
|
||||
|
||||
public function testFindUserOfIdThrowsNotFoundException()
|
||||
{
|
||||
$userRepository = new InMemoryUserRepository([]);
|
||||
$this->expectException(UserNotFoundException::class);
|
||||
$userRepository->findUserOfId(1);
|
||||
}
|
||||
}
|
89
tests/TestCase.php
Normal file
89
tests/TestCase.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use DI\ContainerBuilder;
|
||||
use Exception;
|
||||
use PHPUnit\Framework\TestCase as PHPUnit_TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\App;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Psr7\Factory\StreamFactory;
|
||||
use Slim\Psr7\Headers;
|
||||
use Slim\Psr7\Request as SlimRequest;
|
||||
use Slim\Psr7\Uri;
|
||||
|
||||
class TestCase extends PHPUnit_TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
/**
|
||||
* @return App
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getAppInstance(): App
|
||||
{
|
||||
// Instantiate PHP-DI ContainerBuilder
|
||||
$containerBuilder = new ContainerBuilder();
|
||||
|
||||
// Container intentionally not compiled for tests.
|
||||
|
||||
// Set up settings
|
||||
$settings = require __DIR__ . '/../app/settings.php';
|
||||
$settings($containerBuilder);
|
||||
|
||||
// Set up dependencies
|
||||
$dependencies = require __DIR__ . '/../app/dependencies.php';
|
||||
$dependencies($containerBuilder);
|
||||
|
||||
// Set up repositories
|
||||
$repositories = require __DIR__ . '/../app/repositories.php';
|
||||
$repositories($containerBuilder);
|
||||
|
||||
// Build PHP-DI Container instance
|
||||
$container = $containerBuilder->build();
|
||||
|
||||
// Instantiate the app
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
|
||||
// Register middleware
|
||||
$middleware = require __DIR__ . '/../app/middleware.php';
|
||||
$middleware($app);
|
||||
|
||||
// Register routes
|
||||
$routes = require __DIR__ . '/../app/routes.php';
|
||||
$routes($app);
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @param array $headers
|
||||
* @param array $cookies
|
||||
* @param array $serverParams
|
||||
* @return Request
|
||||
*/
|
||||
protected function createRequest(
|
||||
string $method,
|
||||
string $path,
|
||||
array $headers = ['HTTP_ACCEPT' => 'application/json'],
|
||||
array $cookies = [],
|
||||
array $serverParams = []
|
||||
): Request {
|
||||
$uri = new Uri('', '', 80, $path);
|
||||
$handle = fopen('php://temp', 'w+');
|
||||
$stream = (new StreamFactory())->createStreamFromResource($handle);
|
||||
|
||||
$h = new Headers();
|
||||
foreach ($headers as $name => $value) {
|
||||
$h->addHeader($name, $value);
|
||||
}
|
||||
|
||||
return new SlimRequest($method, $uri, $h, $cookies, $serverParams, $stream);
|
||||
}
|
||||
}
|
2
tests/bootstrap.php
Normal file
2
tests/bootstrap.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
Reference in New Issue
Block a user