Mock Testing
RestServer provides robust mock testing capabilities that allow you to test your API endpoints without making actual HTTP requests.
Mock Request Handler
The MockServer class provides a way to simulate HTTP requests to your API and get back the response that would
be generated.
MockServer::withRequestObject() accepts any PSR-7 request and makes up the server parameters (a local client
address, for instance). To serve real traffic from a PSR-7 request, use Server::withRequestObject(), which keeps
them (see PSR-7 Adapters).
The request goes through the same Psr7RequestAdapter as a real PSR-7 request, so a form body (urlencoded or
multipart) becomes the POST data and the uploaded files. While the request is handled, MockServer also fills
PHP's globals as a web server would ($_SERVER, $_GET, $_POST, $_REQUEST, $_COOKIE, and $_FILES, each
upload in its own temporary file), for code that reads them; after the request they are restored and the temporary
files removed.
The query string can be given in the URI (new Uri('http://localhost/project?page=2')) or in its path
($uri->withPath('/project?page=2'), as php-swagger-test sends it): either way it is the request's query
($request->query(), $_GET).
Basic Example
<?php
use ByJG\RestServer\MockServer;
use ByJG\RestServer\Route\RouteList;
use Nyholm\Psr7\Request;
// Define your routes
$routeDefinition = new RouteList();
$routeDefinition->addClass(MyApiController::class);
// Create a mock PSR-7 request
$request = new Request(
'GET',
'/api/products/123',
['Accept' => 'application/json']
);
// Create a mock handler
$mockHandler = MockServer::mock($routeDefinition, $request);
// Get the response
$statusCode = $mockHandler->getPsr7Response()->getStatusCode();
$headers = $mockHandler->getPsr7Response()->getHeaders();
$body = $mockHandler->getPsr7Response()->getBody()->getContents();
// Now you can make assertions on the response
Mock Response
The MockResponse class helps capture and examine responses:
<?php
use ByJG\RestServer\MockResponse;
use ByJG\RestServer\OutputProcessor\JsonOutputProcessor;
// In test scenarios, you can handle exceptions with mock responses
try {
// Code that might throw an exception
doSomethingThatThrows();
} catch (Exception $ex) {
// Create a mock error response
$result = MockResponse::errorHandlerFromEndpoint(
$ex,
new JsonOutputProcessor(),
$routeDefinition,
'GET',
'/api/resource'
);
// Examine the raw JSON returned by the error handler:
// {"error": {"type": "...", "message": "..."}} (plus "meta" when the exception has metadata)
$error = json_decode($result, true)['error'];
$this->assertSame($ex->getMessage(), $error['message']);
}
Building reusable test harnesses
Larger test suites benefit from a reusable helper that hides the boilerplate of instantiating MockServer and
creating PSR-7 requests. The following trait shows one way to structure that helper:
<?php
namespace Tests\Support;
use ByJG\RestServer\MockServer;
use ByJG\RestServer\OutputProcessor\JsonOutputProcessor;
use ByJG\RestServer\Route\Route;
use ByJG\RestServer\Route\RouteList;
use Nyholm\Psr7\Request;
use Psr\Http\Message\ResponseInterface;
trait ApiTestTrait
{
protected RouteList $routes;
protected function bootRoutes(): void
{
$this->routes = new RouteList();
$this->routes->addRoute(
Route::get('/api/resource')
->withClosure(function ($response, $request) {
$response->write(['status' => 'success']);
})
);
}
protected function request(string $method, string $path, array $headers = [], ?string $body = null): ResponseInterface
{
$psr7Request = new Request($method, $path, $headers, $body);
$handler = new MockServer();
$handler
->withDefaultOutputProcessor(JsonOutputProcessor::class)
->withRequestObject($psr7Request)
->handle($this->routes);
return $handler->getPsr7Response();
}
}
<?php
use PHPUnit\Framework\TestCase;
use Tests\Support\ApiTestTrait;
class MyApiTest extends TestCase
{
use ApiTestTrait;
protected function setUp(): void
{
$this->bootRoutes();
}
public function testGetEndpoint(): void
{
$response = $this->request('GET', '/api/resource');
$this->assertSame(200, $response->getStatusCode());
$this->assertJsonStringEqualsJsonString('{"status":"success"}', (string) $response->getBody());
}
}
The repository’s own test suite includes tests/MockServerTrait.php, demonstrating a more elaborate setup with
pre-registered routes, middlewares, and error handling hooks. Feel free to adapt that trait inside your project if you
need heavier integration fixtures.
Benefits of Mock Testing
- Test API endpoints without running a web server
- Fast execution of tests without network overhead
- Simulate various request scenarios (parameters, headers, body)
- Test error handling and exception cases
- Fully integrated with PHPUnit and other testing frameworks
By using these mock testing capabilities, you can ensure your API works correctly before deploying it to production.