Adam O'Grady

PHPUnit And Guzzle For Testing APIs

Testing code is important, but can often feel like a burden or task, especially if you have strict deadlines. It doesn’t help if your unsure about what tools to use to implement testing on new parts of a project.

PHPUnit is the gold standard framework for testing PHP projects and there are many testing platforms that work directly with it. While it’s perfect for writing small, composable unit tests it can also work perfectly for integration and functional tests.

Guzzle is one of the best PHP HTTP clients available and makes sending and dissecting responses a breeze.

I’ll run through some code that shows you how to test an API, rather than just the code that comprises it.

Setup

We’ll be using Codeception since that’s what I use in some of my personal projects. We need to set up a Codeception test suite:

<?php

use GuzzleHttp\Client;

class ApiTest extends \Codeception\Test\Unit
{
  protected $client;
}

The $client variable will hold the Guzzle client for re-use in multiple tests.

Create a Guzzle Client

In the setUp() function we create the Guzzle client and set up a base_uri for it (in this case, localhost on port 80). If your local development environment is behind SSL or on a different port you might need to update this value.

protected function setUp() {
    $this->client = new Client([
        'base_uri' => 'http://localhost',
        'exceptions' => false
    ]);
}

Of particular importance is the exceptions parameter, which is set to false to stop Guzzle throwing any Exceptions on an error code outside the 200 (success) range. This allows you to test different error codes like parameter mismatch, oversize entities, etc.

Run the tests

Lastly you can start writing tests. In the below example you can see all the tests are POST requests and we test for both valid responses as well as different errors we might experience using this API.

public function testGetExternalId() {
    $response = $this->client->post('/api/example', [
        'form_params' => [
            'email' => 'someone@example.com',
            'phone' => '0400000000'
        ]
    ]);
    $this->assertEquals(200, $response->getStatusCode());

    $response = $this->client->post('/api/3/braze/external-id', [
        'form_params' => [
            'email' => 'someone@example.com'
        ]
    ]);
    $this->assertEquals(400, $response->getStatusCode(), 'Missing phone parameter should return 400 error');

    $response = $this->client->post('/api/3/braze/external-id', [
        'form_params' => [
            'email' => 'someoneexample.com',
            'phone' => '0430000000'
        ]
    ]);
    $this->assertEquals(400, $response->getStatusCode(), 'Malformed email should return 400 error');
}

You can find the full example file as a GitHub Gist.