bentools / test-http-client
Test Symfony applications with HttpClient interface without a real HTTP server
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/bentools/test-http-client
Requires
- php: >=8.2
- symfony/browser-kit: ~6.4 || ~7.0 || ~8.0
- symfony/framework-bundle: ~6.4 || ~7.0 || ~8.0
- symfony/http-client: ~6.4 || ~7.0 || ~8.0
- symfony/http-foundation: ~6.4 || ~7.0 || ~8.0
Requires (Dev)
- bentools/pest-symfony-kernel: ^1.1
- friendsofphp/php-cs-fixer: ^3.93
- pestphp/pest: ^3.0
- phpstan/phpstan: ^2.1.37
- phpunit/phpunit: ^10.0 || ^11.0
- symfony/yaml: ^6.4 || ^7.0
README
Test your Symfony / Api-Platform routes and controllers with symfony/http-client.
This package provides a test implementation of Symfony's HttpClientInterface that uses KernelBrowser internally,
allowing you to test your HTTP endpoints as if you were making real HTTP requests, but without the overhead of running an actual HTTP server.
Compatible with both PHPUnit and Pest.
Example
// src/Controller/HealthController.php namespace App\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; final readonly class HealthController { #[Route('/health')] public function __invoke(): JsonResponse { return new JsonResponse(['status' => '😎']); } }
Pest
// tests/Controller/HealthControllerTest.php use BenTools\TestHttpClient\TestHttpClient; use function BenTools\Pest\Symfony\inject; it('works', function () { $client = inject(TestHttpClient::class); // <-- See package `bentools/pest-symfony-kernel` $response = $client->request('GET', '/health'); expect($response)->toBeSuccessful() ->and($response)->toHaveStatusCode(200) ->and($response)->toHaveHeader('Content-Type', 'application/json') ->and($response)->toHaveJsonStructure(['status']) ->and($response['status'])->toBe('😎') ; });
PHPUnit
// tests/Controller/HealthControllerTest.php use BenTools\TestHttpClient\TestHttpClient; class HealthControllerTest extends WebTestCase { public function testHealth(): void { $client = static::getContainer()->get(TestHttpClient::class); $response = $client->request('GET', '/health'); $this->assertSame(200, $response->getStatusCode()); $this->assertContains('application/json', $response->getHeaders()['content-type'] ?? ''); $this->assertArrayHasKey('status', $response); $this->assertEquals('😎', $response['status']); } }
Features
- ✅ Implements
HttpClientInterface- Drop-in replacement for real HTTP clients in tests - ✅ No HTTP server required - Uses Symfony's
KernelBrowserunder the hood - ✅ Fast integration tests - Test your API endpoints in milliseconds
- ✅ Access to internals - Get the container, profiler, cookies, and more
- ✅ Pest expectations included - Custom expectations for testing responses
- ✅ Full HTTP feature support - Headers, authentication, JSON, query parameters, etc.
Installation
composer require --dev bentools/test-http-client
Symfony Bundle Integration
For Symfony applications, you can register the bundle to automatically wire the TestHttpClient service:
1. Register the Bundle
Add the bundle to your config/bundles.php (only in test environment):
// config/bundles.php return [ // ... other bundles BenTools\TestHttpClient\Bundle\TestHttpClientBundle::class => ['test' => true], ];
2. Use the Service
Once registered, the TestHttpClient service is automatically available in your test environment:
use BenTools\TestHttpClient\TestHttpClient; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class ApiTest extends WebTestCase { public function testUsersList(): void { $client = static::getContainer()->get(TestHttpClient::class); $response = $client->request('GET', '/api/users'); $this->assertSame(200, $response->getStatusCode()); } }
For Pest tests:
it('returns users list', function () { $client = container()->get(TestHttpClient::class); $response = $client->request('GET', '/api/users'); expect($response)->toHaveStatusCode(200); });
Note
If you prefer to instantiate TestHttpClient manually without registering the bundle, you can still do so as shown in the Quick Start section below.
Quick Start
With Pest
use BenTools\TestHttpClient\TestHttpClient; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; uses(WebTestCase::class); it('returns users list', function () { $client = new TestHttpClient(static::createClient()); $response = $client->request('GET', '/api/users'); expect($response) ->toHaveStatusCode(200) ->toHaveJsonStructure() ->toHaveHeader('content-type', 'application/json'); $data = $response->toArray(); expect($data)->toHaveKey('users'); });
With PHPUnit
use BenTools\TestHttpClient\TestHttpClient; public function testReturnsUsersList(): void { $client = new TestHttpClient(static::createClient()); $response = $client->request('GET', '/api/users'); $this->assertSame(200, $response->getStatusCode()); $this->assertArrayHasKey('users', $response->toArray()); }
Bearer Authentication
$response = $client->withAuthBearer('your-token-here')->request('GET', '/api/admin');
Access Cookies
$cookieJar = $client->kernelBrowser->getCookieJar(); $cookies = $cookieJar->all();
Performance Optimization
By default, Symfony reboots the kernel between requests. For better performance in tests with multiple requests:
$client = new TestHttpClient($kernelBrowser); $client->kernelBrowser->disableReboot(); // Make multiple requests - kernel stays booted $response1 = $client->request('GET', '/api/users'); $response2 = $client->request('GET', '/api/posts'); $response3 = $client->request('GET', '/api/comments');
Pest Expectations
If you're using Pest, the package includes custom expectations for testing responses:
use BenTools\TestHttpClient\TestHttpClient; it('tests various response aspects', function () { $client = new TestHttpClient(static::createClient()); $response = $client->request('GET', '/api/users'); // Status code expect($response)->toHaveStatusCode(200); // Success (2xx) expect($response)->toBeSuccessful(); // Client error (4xx) expect($response)->toBeClientError(); // Server error (5xx) expect($response)->toBeServerError(); // Headers expect($response)->toHaveHeader('content-type'); expect($response)->toHaveHeader('cache-control', 'max-age=3600'); // JSON expect($response)->toHaveJsonStructure(); // JSON structure expect($response)->toHaveJsonStructure(['users', 'total', 'page']); });
Available Expectations
toHaveStatusCode(int $code)- Assert status codetoBeSuccessful()- Assert 2xx statustoBeClientError()- Assert 4xx statustoBeServerError()- Assert 5xx statustoHaveHeader(string $name, ?string $value = null)- Assert header exists (optionally with value)toHaveJsonStructure()- Assert content-type is JSONtoHaveJsonStructure(array $keys)- Assert JSON contains specific keys
Credits
Borrowed and adapted from Api-Platform's TestClient.
License
MIT.