Resource icon

xF2 Dev Tutorials Unit testing XenForo addons - tutorial

  • Feature: added new functionality to Interacts with Container
    • mockService
  • Feature: Interacts with Http, new function:
    • fakesHttp

mockService
Mock a service factory builder in the container.

Parameters
  • shortName - the short name of the service class to be mocked
  • mock - optional - the mock closure to define expectations on
Example:
PHP:
<?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) {
            $mock->expects()->stop('list')->once();
        });

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

fakesHttp
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.

Parameters:
  • 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
Example:
PHP:
<?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
        $this->fakesHttp([
            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
        $this->expectException(RequestException::class);

        // 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
  • Like
Reactions: JohanVandaele
731Threads
2,287Messages
63,845Members
maxmaxyameLatest member
Back