Testing Your Application

This chapter describes how to test your application against your reverse proxy.

The FOSHttpCache library provides base test case classes to help you write functional tests. This is helpful to test the way your application sets caching headers and invalidates cached content.

By having your test classes extend one of the test case classes, you get:

  • independent tests: all previously cached content is removed in the tests setUp method. The way this is done depends on which reverse proxy you use;
  • an instance of this library’s client that is configured to talk to your reverse proxy server. See reverse proxy specific sections for details;
  • convenience methods for executing HTTP requests to your application: $this->getHttpClient() and $this->getResponse();
  • custom assertions assertHit and assertMiss for validating a cache hit/miss.

The recommended way to configure the test case is by setting constants in your phpunit.xml. Alternatively, you can override the getter methods.

You will need to run a web server to provide the PHP application you want to test. The test cases only handle running the caching proxy. With PHP 5.4 or newer, the easiest is to use the PHP built in web server. See the WebServerListener class in tests/Functional and how it is registered in phpunit.xml.dist.

Setting Constants

Compare this library’s configuration to see how the constants are set:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit ...>
        <const name="NGINX_FILE" value="./tests/Functional/Fixtures/nginx/fos.conf" />
        <const name="WEB_SERVER_HOSTNAME" value="localhost" />
        <const name="WEB_SERVER_PORT" value="8080" />
        <const name="WEB_SERVER_DOCROOT" value="./tests/Functional/Fixtures/web" />
    </php>
</phpunit>

Overriding Getters

You can override getters in your test class in the following way:

use FOS\HttpCache\Test\VarnishTestCase;

class YourFunctionalTest extends VarnishTestCase
{
    protected function getVarnishPort()
    {
        return 8000;
    }
}

VarnishTestCase

Configuration

By default, the VarnishTestCase starts and stops a Varnish server for you. Make sure symfony/process is available in your project:

$ composer require symfony/process

Then set your Varnish configuration (VCL) file. All available configuration parameters are shown below.

Constant Getter Default Description
VARNISH_FILE getConfigFile()   your Varnish configuration (VCL) file
VARNISH_BINARY getBinary() varnishd your Varnish binary
VARNISH_PORT getCachingProxyPort() 6181 port Varnish listens on
VARNISH_MGMT_PORT getVarnishMgmtPort() 6182 Varnish management port
VARNISH_CACHE_DIR getCacheDir() sys_get_temp_dir() + /foshttpcache-varnish directory to use for cache
VARNISH_VERSION getVarnishVersion() 3 installed varnish application version
WEB_SERVER_HOSTNAME getHostName()   hostname your application can be reached at

Enable Assertions

For the assertHit and assertMiss assertions to work, you need to add a custom X-Cache header to responses served by your Varnish.

NginxTestCase

Configuration

By default, the NginxTestCase starts and stops the NGINX server for you and deletes all cached contents. Make sure symfony/process is available in your project:

$ composer require symfony/process

You have to set your NGINX configuration file. All available configuration parameters are shown below.

Constant Getter Default Description
NGINX_FILE getConfigFile()   your NGINX configuration file
NGINX_BINARY getBinary() nginx your NGINX binary
NGINX_PORT getCachingProxyPort() 8088 port NGINX listens on
NGINX_CACHE_PATH getCacheDir() sys_get_temp_dir() + /foshttpcache-nginx directory to use for cache Must match proxy_cache_path directive in your configuration file.
WEB_SERVER_HOSTNAME getHostName()   hostname your application can be reached at

Enable Assertions

For the assertHit and assertMiss assertions to work, you need to add a custom X-Cache header to responses served by your Nginx.

SymfonyTestCase

This test case helps to test invalidation requests with a symfony application running the Symfony HttpCache and invalidating its cache folder to get reliable tests.

The SymfonyTestCase does automatically start a web server. It is assumed that the web server you run for the application has the HttpCache integrated.

Configuration

Constant Getter Default Description
WEB_SERVER_HOSTNAME getHostName()   hostname your application can be reached at
WEB_SERVER_PORT getConfigFile()   The port on which the web server runs
SYMFONY_CACHE_DIR getCacheDir() sys_get_temp_dir() + /foshttpcache-nginx directory to use for cache Must match the configuration of your HttpCache and must be writable by the user running PHPUnit.

Enable Assertions

For the assertHit and assertMiss assertions to work, you need to add debug information in your AppCache. Create the cache kernel with the option 'debug' => true and add the following to your AppCache:

public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
    $response = parent::handle($request, $type, $catch);

    if ($response->headers->has('X-Symfony-Cache')) {
        if (false !== strpos($response->headers->get('X-Symfony-Cache'), 'miss')) {
            $state = 'MISS';
        } elseif (false !== strpos($response->headers->get('X-Symfony-Cache'), 'fresh')) {
            $state = 'HIT';
        } else {
            $state = 'UNDETERMINED';
        }
        $response->headers->set('X-Cache', $state);
    }

    return $response;
}

The UNDETERMINED state should never happen. If it does, it means that your HttpCache is not correctly set into debug mode.

Usage

This example shows how you can test whether the caching headers your application sets influence Varnish as you expect them to:

use FOS\HttpCache\Test\VarnishTestCase;

class YourFunctionalTest extends VarnishTestCase
{
    public function testCachingHeaders()
    {
        // Varnish is restarted, so you don’t have to worry about previously
        // cached content. Before continuing, the VarnishTestCase waits for
        // Varnish to become available.

        // Retrieve an URL from your application
        $response = $this->getResponse('/your/resource');

        // Assert the response was a cache miss (came from the backend
        // application)
        $this->assertMiss($response);

        // Assume the URL /your/resource sets caching headers. If we retrieve
        // it again, we should have a cache hit (response delivered by Varnish):
        $response = $this->getResponse('/your/resource');
        $this->assertHit($response);
    }
}

This example shows how you can test whether your application purges content correctly:

public function testCachePurge()
{
    // Again, Varnish is restarted, so your test is independent from
    // other tests

    $url = '/blog/articles/1';

    // First request must be a cache miss
    $this->assertMiss($this->getResponse($url));

    // Next requests must be a hit
    $this->assertHit($this->getResponse($url));

    // Purge
    $this->varnish->purge('/blog/articles/1');

    // First request after must again be a miss
    $this->assertMiss($this->getResponse($url));
}

Tests for Nginx look the same but extend the NginxTestCase. For more ideas, see this library’s functional tests in the tests/Functional/ directory.