Resource icon

Unit testing XenForo addons - tutorial

XenForo 2.2 implements Swiftmail 6, which changes some of the method/interface signatures - so I've had to push a new major release for XF 2.2 compatibility.

XenForo 2.1 addons should use Unit Test Framework v1.x
XenForo 2.2 addons should use Unit Test Framework v2.x
  • bugfix: fixed typo in function name assertSimpleCacheEqual => assertSimpleCacheEquals
  • bugfix: close the database connection on tearDown to avoid connection limit issues (unless it's been mocked)
  • Like
Reactions: Earl
  • Feature: added new functionality to Interacts with Container
    • mockService
  • Feature: Interacts with Http, new function:
    • fakesHttp

Mock a service factory builder in the container.

  • shortName - the short name of the service class to be mocked
  • mock - optional - the mock closure to define expectations on
<?php namespace Tests\Unit;

use Tests\TestCase;
use XF\Http\Request;

class ServiceTest extends TestCase
    public function test_service()
        // mock our service class
        $this->mockService('XF:User\EmailStop', function ($mock) {

        // execute some test code which causes the mocked code to be executed, for example
        $emailStop = $this->app()->service('XF:User\EmailStop');

Allow us to assert that certain HTTP requests were (or were not) sent as a result of executing our test code, and to supply mock HTTP responses without side-effects (ie no requests actually sent).

This function relies on the Mock Handler and History Middleware provided by the Guzzle HTTP library used by XenForo.

Refer to the Guzzle documentation Testing Guzzle Clients for more information on how the Mock Handler and History Middleware works.

  • array responseStack - an array of Psr7 Responses or Request Exceptions to return - one for each request made
  • bool untrusted - set to true when using the untrusted client in XenForo
Assertions available:
  • assertHttpRequestSent
  • assertHttpRequestSentTimes
  • assertHttpRequestNotSent
  • assertNoHttpRequestSent
<?php namespace Tests\Unit;

use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Exception\RequestException;
use Tests\TestCase;

class HttpTest extends TestCase
    public function test_http()
        // tell Guzzle not to send requests, but to instead return our mock responses, one for each
        // request that we make
            new Response(200, ['X-Foo' => 'Bar'], 'Hello, World'),
            new Response(202, ['Content-Length' => 0]),
            new RequestException('Error Communicating with Server', new Request('GET', 'test'))

        // our third response generates an exception

        // execute some code which sends an Http request
        $response1 = $this->app()->http()->client()->get('/');
        $response2 = $this->app()->http()->client()->get('/foo');
        $response3 = $this->app()->http()->client()->get('/bar');

        // assert something about the requests that were sent
        $this->assertHttpRequestSent(function ($request) {
            return strval($request->getUri()) == '/' OR strval($request->getUri()) == '/foo';

        // assert something about our responses
        $this->assertEquals(200, $response1->getStatusCode());
        $this->assertEquals(202, $response2->getStatusCode());
  • Feature: added new functionality to Interacts with Extension
    • isolateAddon
  • Feature: Interacts with Registry - adds:
    • fakesRegistry
  • Feature: Interacts with Filesystem - adds:
    • swapFs
    • mockFs
  • bugfix: after mocking the database, set up the entity manager again, so we get the mocked database
  • bugfix: should pass options array through to parent
  • bugfix: cleaned up function visibility for consistency
  • bugfix: override protected function preLoadData so we can call it directly when faking the registry