Making HTTP requests programmatically in Kernel tests

Last updated on
6 April 2023

While in general, Functional tests are designed for the testing of page loads, it's possible to test these in Kernel tests too. The advantage is that Kernel tests are much faster to run, because they only set up what they need to.

The trade-off is that you don't get the HTML output from the test, and writing the setup for the test is harder, as any config and database schema the test uses need to be set up directly.

Using Kernel tests for testing requests is particularly suited to:

  • Tests that only check the HTTP status of the response, for example when checking access to a page. The faster running time is particularly useful if many different combinations need to be tested for.
  • Tests that make non-HTML requests, such as testing REST endpoints, or AJAX responses.

To make an HTTP request in a kernel test, use the HTTP kernel:

    $http_kernel = $this->container->get('http_kernel');

    $request = Request::create('/node/' . $node->id());

    $response = $http_kernel->handle($request);
    $this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());

If making a request for a REST resource, the Accept header must be set:

    $request = Request::create('/node/' . $node->id());
    $request->headers->set('Accept', 'application/json');

The same $request object can be passed to the HTTP kernel multiple times; there is no need to recreate it after making changes to the site to test a different case.

The content of the request can be obtained thus:

$content = $response->getContent();
// This allows use of the methods in AssertContentTrait.
$this->setRawContent($content);

Pitfalls

Making multiple requests within the same session can cause problems with code in Drupal that assumes that the code lifecycle is a single HTTP request.

Of particular note is the Entity access system, which currently uses a static class property as a cache (this is a bug in core). This means that the access data for an entity will be cached and not get invalidated when a change is made to the entity or to other parts of the site such as user permissions. The access cache should be flushed any time changes are made:

    $this->entityTypeManager->getAccessControlHandler('node')->resetCache();

Further reading

Help improve this page

Page status: No known problems

You can: