Episode 004 – Mock Test Doubles


In Episode 4 of Testing All The Things we continue to create the driving licence generator we started in the previous two videos. In this video we create a mock random number generator to create random digits to the end of the driving licence number.

You can find all the Test Double code in this GitHub repository or just the code created for the spy functionality in this commit

Episode 002 – Stub Test Doubles


In episode 2 of Testing All The Things we start to exploring Test Doubles. Test doubles are used to isolate the code under test from its dependencies. Test doubles imitate the functionality of a dependency.

Creating test doubles do not require the use of a mocking framework. In the following videos we will not use a mocking framework so we can concentrate of the theory.

In the first video we are looking at the simplest form of Test Double, Stubs.

Writing A Testable API Client Library


Recently at work I had to create a PHP client library for one of our REST microservices. The client library will be used by many of our projects. I wanted to implement the library using test driven development

I had some trouble finding any advice or examples of client libraries that had be implemented using Test Driven Development where the tests did not actually rely on making calls the service.

I wanted Guzzle to be a dependency of the client library. Doing this would allow me to pass in a mocked Guzzle instance to my PHPSpec tests .This would mean my unit tests would not rely on communicating with API to pass.

However I did not want users of the client library to have to worry about the Guzzle dependency.

After a discussion with some colleagues I decided the best approach was have the client object require Guzzle as a constructor dependency but provide a static factory method for client library users to use for construction without providing the Guzzle dependency.

class PokeClient
{
    /**
     * @var \GuzzleHttp\ClientInterface
     */
    private $httpClient;

    /**
     * @var \Braddle\PokeApi\Factory\PokemonFactory
     */
    private $pokemonFactory;

    /**
     * PokeClient constructor.
     */
    public function __construct(
        ClientInterface $httpClient, 
        PokemonFactory $pokemonFactory
    ) {
        $this->httpClient = $httpClient;
        $this->pokemonFactory = $pokemonFactory;
    }

    /**
     * @return Client
     */
    public static function create()
    {
        $httpClient = new Client(
            ['base_uri' => 'http://pokeapi.co/api/v2/']
        );
        return new self($httpClient, new PokemonFactory());
    }

Any users of the client library now have a very simple way to instantiate the client library.

In this example the base URI is hard coded as the is only one version of the service. If you have different environments to work with you can pass  URI or a constant for the environment in to the create() function.

Creating an instance of the PokeClient is now as simple at this

$pokeCLient = PokeClient::create();

This implementation allows me to mock Guzzle calls in my PHPSpec tests.

class PokeClientSpec extends ObjectBehavior
{
    function let(Client $httpClient, PokemonFactory $pokemonFactory)
    {
        $this->beConstructedWith($httpClient, $pokemonFactory);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType('Braddle\PokeApi\PokeClient');
    }

    function it_should_be_able_to_create_an_instance_of_itself()
    {
        $this::create()->shouldReturnAnInstanceOf(PokeClient::class);
    }

    function it_should_return_a_pokemon_when_attmepting_to_find_one_by_id(
        Client $httpClient,
        PokemonFactory $pokemonFactory,
        Response $response,
        StreamInterface $stream,
        Pokemon $pokemon
    ) {
        $pokemonId = 975;
        $json = json_encode(
            [
                'id'              => 34,
                'name'            => '',
                'base_experience' => 4,
                'height'          => 15,
                'is_default'      => false,
                'order'           => 1,
                'weight'          => 468,
            ]
        );

        $response->getBody()->willReturn($stream);
        $stream->getContents()->willReturn($json);
        $httpClient->request('GET', 'pokemon/' . $pokemonId)
            ->willReturn($response);
        $pokemonFactory->createPokemon(Argument::any())
            ->willReturn($pokemon);
        
        $this->findPokemonById($pokemonId)
            ->shouldReturnAnInstanceOf(Pokemon::class);
    }
}

This method also allowed my to add addition Guzzle options for my Behat integration tests

Feature: Getting Pokemon

    Scenario: Ensure that is it possible to find a Pokemon by its ID
        Given The client has been instantiated
        When I try to find a Pokemon by ID 1
        Then I should have been returned a Pokemon
class FeatureContext implements Context, SnippetAcceptingContext
{
    /**
     * @var PokeClient
     */
    private $client;
 
    /**
     * @var Pokemon
     */
    private $pokemon;
 
    /**
     * Initializes context.
     *
     * Every scenario gets its own context instance.
     * You can also pass arbitrary arguments to the
     * context constructor through behat.yml.
     */
    public function __construct()
    {
    }
    /**
     * @Given The client has been instantiated
     */
    public function theClientHasBeenInstantiated()
    {
        $this->client = PokeClient::create();
    }
 
    /**
     * @When I try to find a Pokemon by ID :id
     */
    public function iTryToFindAPokemonById($id)
    {
        $this->pokemon = $this->client->findPokemonById($id);
    }
 
    /**
     * @Then I should have been returned a Pokemon
     */
    public function iShouldHaveBeenReturnedAPokemon()
    {
        if (!$this->pokemon instanceof Pokemon) {
            throw new \Exception('No Pokemon found');
        }
    }
}

See the full example client library for the Pokemon API in this GitHub repository.

Doctrine Entity Event


In my first post on Single Table Inheritance I had some example code that made use of a $tax variable to demonstrate where tax is added or removed. This simplification hides some complexity of the actual implementation.

In the actual implementation I needed to have access to a TaxCalculator object in all Price entities. The issue I had was how to ensure this happens without having to remember to manually inject the TaxCalculator everywhere Price entities are retrieved or persisted.

To do this I used a Doctrine feature called Entity Listeners. The Listener functionality allows you to access entities during a number of Doctrine operations.  Once configured you are able to hook into a number of different events before or after various CRUD events, they are:

  • preFlush
  • postLoad
  • PrePersist
  • PostPersist
  • PreUpdate
  • PostUpdate
  • PostRemove
  • PreRemove

The listening function is passed the entity that triggering the event and an instance of Doctrine\Common\EventArgs. In my example i do not use the EventArgs object. It can be used to give you another way to access the entity triggering the event or an instance of Doctrine/ORM/EntityManager.

The following Doctrine YAML configuration specifies the Entity Event Listener class (Braddle\EntityListener) for the Price entities.

Braddle\Entity\Price:
  type: entity
  table: price
  inheritanceType: SINGLE_TABLE
  discriminatorColumn:
    name: type
    type: string
  discriminatorMap:
    including_tax: PriceIncludingTax
    excluding_tax: PriceExcludingTax
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  fields:
    price:
      type: float
  entityListeners:
    Braddle\EntityListener:

Here is the implementation of my Entity Event Listener (Braddle\EntityListener) this listener injects a TaxCalculator into price entities. I have only used the postLoad and postPersist functions so that i can ensure that new Prices have a TaxCalculator injected when they are saved and all existing Prices when they are retrieved from the database.

namespace Braddle;

use Braddle\Entity\Price;

class EntityListener
{

    /**
     * Fired before an object is about to be saved by doctrine
     *
     * @param PricingConfigAware $object The model to inject the price config into
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     *
     * @return void
     */
    public function prePersist(Price $object)
    {
        $object->setTaxCalculator($this->getTaxCalculator());
    }

    /**
     * Fired before an object is about to be saved by doctrine
     *
     * @param PricingConfigAware $object The model to inject the price config into
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     *
     * @return void
     */
    public function postLoad(Price $object)
    {
        $object->setTaxCalculator($this->getTaxCalculator());
    }

    /**
     * @return \Braddle\TaxCalculator
     */
    private function getTaxCalculator()
    {
        return new TaxCalculator(20);
    }
}

You can find the full example application using the Doctrine Entity Event in this GitHub Repository.