09/02/2019 - PHPUNIT, SYMFONY
In this example we are going to override Symfony private services and functional test them with PHPUnit.
namespace App\Util;
interface HttpClientInterface
{
public function isTokenValid(string $token): bool;
}
namespace App\Util;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
class HttpClient implements HttpClientInterface
{
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function isTokenValid(string $token): bool
{
/** @var Response $response */
$response = $this->client->request(
'GET',
'external/api/endpoint',
['headers' => ['Authorization' => $token]]
);
return 'true' === $response->getBody()->getContents();
}
}
# config/services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\Util\HttpClient:
arguments:
- '@GuzzleHttp\Client'
If we are to use a functional test for the client class above, we would end up calling external/api/endpoint
everytime when we run the tests which is something we don't want. To prevent such issue, we want to create a "mock" version of it, test
environment specific services_test.yaml
file and use it in out tests instead.
# tests/Functional/Mock/Util/HttpClientMock.php
namespace Tests\Functional\Mock\Util;
use App\Util\HttpClientInterface;
class HttpClientMock implements HttpClientInterface
{
public function isTokenValid(string $token): bool
{
return $token === 'Bearer valid-token';
}
}
# config/packages/test/services_test.yaml
services:
_defaults:
public: true
test.App\Util\HttpClient: '@App\Util\HttpClient'
declare(strict_types=1);
namespace Tests\Functional\Controller;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Tests\Functional\Mock\Util\HttpClientMock;
class YourControllerTest extends WebTestCase
{
/**
* @test
*/
public function return_unauthorised_response_if_the_token_is_not_valid(): void
{
$client = static::createClient();
$client->getContainer()->set('test.App\Util\HttpClient', new HttpClientMock());
$client->request(Request::METHOD_GET, '/', [], [], ['HTTPS' => true, 'HTTP_authorization' => 'Bearer invalid-user-token']);
self::assertSame(Response::HTTP_UNAUTHORIZED, $client->getResponse()->getStatusCode());
}
/**
* @test
*/
public function return_authorised_response_if_the_token_is_valid(): void
{
$client = static::createClient();
$client->getContainer()->set('test.App\Util\HttpClient', new HttpClientMock());
$client->request(Request::METHOD_GET, '/', [], [], ['HTTPS' => true, 'HTTP_authorization' => 'Bearer valid-user-token']);
self::assertSame(Response::HTTP_OK, $client->getResponse()->getStatusCode());
}
}