Hello everyone!

We have been investing plenty of personal time and energy for many years to share our knowledge with you all. However, we now need your help to keep this blog running. All you have to do is just click one of the adverts on the site, otherwise it will sadly be taken down due to hosting etc. costs. Thank you.

In this example we are going to override Symfony private services and functional test them with PHPUnit.


HttpClient


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'

Changes


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'

Test class


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());
}
}