psr-mock/http-message-implementation
Lightweight PSR-7 HTTP message implementation mock for testing libraries and SDKs without hard dependencies. Strictly follows PSR behavior and includes a developer-friendly API to debug and fix failing tests faster. For dev use only (PHP 8.1+).
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require --dev psr-mock/http-message-implementation:^1.0
composer.json under require-dev if not using autoloader.First Use Case: Mocking a Request
use PsrMock\Http\Message\MockRequest;
use Psr\Http\Message\RequestInterface;
$request = MockRequest::create()
->withMethod('GET')
->withUri('https://example.com/api')
->withHeader('Accept', 'application/json');
First Use Case: Mocking a Response
use PsrMock\Http\Message\MockResponse;
$response = MockResponse::create()
->withStatus(200)
->withHeader('Content-Type', 'application/json')
->withBody('{"status": "success"}');
Where to Look First
src/ directory for core classes (MockRequest, MockResponse, MockStream).tests/ for usage examples and edge cases.public function testGetUserProfile()
{
$request = MockRequest::create()
->withMethod('GET')
->withUri('/users/123')
->withHeader('Authorization', 'Bearer token123');
$response = $this->app->handle($request);
$this->assertEquals(200, $response->getStatusCode());
}
public function testFetchDataFromExternalApi()
{
$mockResponse = MockResponse::create()
->withStatus(200)
->withBody('{"data": "test"}');
// Mock GuzzleHttp\Client or similar to return $mockResponse.
$service = new ExternalApiService($mockClient);
$result = $service->fetchData();
$this->assertEquals(['data' => 'test'], json_decode($result, true));
}
$request = MockRequest::create()
->withMethod('POST')
->withUri('/submit')
->withHeader('Content-Type', 'application/json')
->withBody(json_encode(['key' => 'value']));
public function testMultipleRequestScenarios(array $method, string $uri, array $headers)
{
$request = MockRequest::create()
->withMethod($method)
->withUri($uri)
->withHeaders($headers);
// Test logic here...
}
public function requestProvider()
{
return [
['GET', '/users', ['Accept' => 'application/json']],
['POST', '/users', ['Content-Type' => 'application/json']],
];
}
public function testLaravelHttpResponse()
{
$response = MockResponse::create()
->withStatus(200)
->withHeader('Content-Type', 'text/html')
->withBody('<html>Test</html>');
$this->get('/test')
->assertOk()
->assertSee('<html>Test</html>');
}
use PsrMock\Http\Message\MockStream;
$stream = MockStream::createFromContent('file_content')
->withSize(1024)
->withMetadata(['custom' => 'metadata']);
$request = MockRequest::create()
->withUploadedFile('file', $stream);
class CustomMockRequest extends MockRequest
{
public function withCustomHeader(string $name, string $value): self
{
return $this->withAddedHeader($name, $value);
}
}
public function testRequestHeadersProvider()
{
$this->assertRequestHeaders(
MockRequest::create()->withHeader('X-Test', '1'),
['X-Test' => '1']
);
}
// ❌ Wrong: Modifies nothing
$request->withMethod('GET')->withUri('/test'); // Returns void if not assigned
// ✅ Correct: Assign result
$request = $request->withMethod('GET')->withUri('/test');
$request->withHeader('content-type', 'text/plain'); // Preserves case
$request->getHeader('Content-Type'); // Returns 'content-type'
$stream = $request->getBody();
$detached = $stream->detach(); // $stream is now detached
$request->getBody(); // Returns $detached
parse_url() under the hood. Ensure URIs are valid:
// ❌ May throw exception
$request->withUri('invalid:uri');
// ✅ Safe
$request->withUri('https://example.com');
$body = $response->getBody();
$body->rewind(); // Reset pointer
$content = $body->getContents(); // Read again
# Check PHP version
php -v
^0.9 (last version supporting PHP 7.4+).$headers = $request->getHeaders();
$body = $request->getBody()->getContents();
dd($headers, $body);
$this->assertInstanceOf(RequestInterface::class, $request);
$this->assertInstanceOf(StreamInterface::class, $request->getBody());
if ($request->getBody()->isSeekable()) {
// Stream is still attached
}
use PHPUnit\Framework\Assert;
public function assertRequestMatches(RequestInterface $request, string $method, string $uri, array $headers = [])
{
Assert::assertEquals($method, $request->getMethod());
Assert::assertEquals($uri, (string) $request->getUri());
foreach ($headers as $name => $value) {
Assert::assertEquals($value, $request->getHeaderLine($name));
}
}
class RequestFactory
{
public static function createGet(string $uri, array $headers = []): MockRequest
{
return MockRequest::create()
->withMethod('GET')
->withUri($uri)
->withHeaders($headers);
}
}
class LoggingMockRequest extends MockRequest
{
public function withMethod(string $method): self
{
error_log("Method changed to: {$method}");
return parent::withMethod($method);
}
}
Http Facade$mockResponse = MockResponse::create()->withStatus(200);
Http::fake($mockResponse);
config/ or service provider setup is needed.nyholm/psr7 or guzzlehttp/psr7). The mock implements the interfaces but relies on underlying implementations for some features (e.g., streams).How can I help you explore Laravel packages today?