Search code examples
phpjsonapiphpunitweb-api-testing

how to make PHPUnit stop intercepting exceptions?


I am working with a internal framework where every exception is catched by an error handler and returned in a proper JSON error response, suitable for a RESTFul API.

Then I have a suite of tests, which are API tests, that are mainly testing that the API returns the proper JSON responses with the expected error codes.

For every test, the global variables are modified (and then restored) to emulate a different HTTP request. I do it that way to avoid the overload of doing cURL tests (through Guzzle or similar), and cause under the CLI environment, the code does not know the server's url.

<?php
// ... example, part of a base ApiTestCase class:

// Override globals (should be backed up by PHPUnit)
$_SERVER['REQUEST_METHOD']     = $request->method;
$_SERVER['QUERY_STRING']       = http_build_query($request->parameters);
$_SERVER['PATH_INFO']          = $request->path;
$_SERVER['REQUEST_URI']        = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
$_SERVER['REQUEST_TIME']       = time();
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true);
$_SERVER['HTTP_COOKIE']        = '';

// Set headers, cookies and parameters
foreach ($request->headers as $k => $v) {
  $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v;
}
if ($_SERVER['HTTP_COOKIE']) {
  $GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']);
} else {
  $GLOBALS['_COOKIE'] = [];
}
$GLOBALS['_REQUEST'] = $request->parameters;

$responseBody = $app->start();

$response->httpCode = http_response_code();
$response->body     = $responseBody ? @json_decode($responseBody) : null;
$response->headers  = headers_list();

(I know that changing globals this way is not nice, and the framework should not rely on globals directly, but I have still to deal with legacy code.)

Then here comes the problem: when I try to test JSON error responses: PHPUnit intercepts the thrown exception (before the handler I mentioned in the beginning), so the framework has no chance to convert it to JSON and return the proper response.

I tried to find something in the PHPUnit manual to disable the PHPUnit error handler with no luck.

What could I do in this case? Thanks


Solution

  • The only solution I implemented that solves my problem is to not delegate the exception handler the responsibility to build and send the API error responses, but catch exceptions in the top level of your application.

    In the catch I have an exception-to-error-response converter that takes care of that (or re-throws the exception when convenient), so the errors that are not critical (like the ones producing HTTP 4xx responses) are not popping up in the PHPUnit tests anymore. My PHPUnit tests are also now able to deal with PSR-7 HTTP Response objects, instead of capturing the output buffer.