Testing APIs

Introduction

Integration tests are a great way to make sure your application is working end-to-end as expected. Aphiria, with the help of PHPUnit, comes with some great tools to help you send requests to your application and parse the responses. Aphiria uses automatic content-negotiation in your integration tests, which frees you to make assertions using your app's models without worrying about how to (de)serialize data. The integration tests won't actually send a request over HTTP, either. Instead, it creates an in-memory instance of your application, and sends the requests to that. The nice part about not having to go over HTTP is that you don't worry about having to set up firewall rules for testing your application in staging slots.

Note: All the examples here are assuming that you're using the skeleton app, and extending IntegrationTestCase. By default, tests will run in the testing environment. If you wish to change this, you can by editing the APP_ENV value in phpunit.xml.dist.

Sending Requests

Sending a request is very simple:

use App\Tests\IntegrationTestCase;

class BookQueryTest extends IntegrationTestCase
{
    public function testQueryYieldsCorrectResult(): void
    {
        $response = $this->get('/books/search?query=great%20gatsby');
        $this->assertStatusCodeEquals(200, $response);
        $this->assertParsedBodyEquals(new Book('The Great Gatsby'), $response);
    }
}

Use the following methods to send requests and get responses:

When specifying a URI, you can use either pass just the path or the fully-qualified URI. If you're using a path, the APP_URL environment variable will be prepended automatically.

$this->get('/books/123');

// Or

$this->get('http://localhost/books/123');

You can pass in headers in your calls:

$this->delete('/users/123', ['Authorization' => 'Basic Zm9vOmJhcg==']);

All methods except get() also support passing in a body:

$this->post('/users', [], new User(1, 'foo@bar.com'));

If you pass in an instance of IBody, that will be used as the request body. Otherwise, content negotiation will be applied on the value you pass in.

Response Assertions

Response assertions can be used to make sure the data sent back by your application is correct. Let's look at some examples of assertions:

Name Description
assertCookieEquals() Asserts that the response sets a cookie with a particular value
assertHasCookie() Asserts that the response sets a cookie
assertHasHeader() Asserts that the response sets a particular header
assertHeaderEquals() Asserts that the response sets a header with a particular value
assertHeaderMatchesRegex() Asserts that the response sets a header whose value matches a regular expression
assertParsedBodyEquals() Asserts that the parsed response body equals a particular value
assertParsedBodyPassesCallback() Asserts that the parsed response body passes a callback function
assertStatusCodeEquals() Asserts that the response status code equals a particular value
// Assert that the response sets a cookie named "userId" with value "123"
$this->assertCookieEquals('123', $response, 'userId');
// Assert that the response sets a cookie named "userId"
$this->assertHasCookie($response, 'userId');

assertHasHeader

// Assert that the response sets a header named "Authorization"
$this->assertHasHeader($response, 'Authorization');

assertHeaderEquals

// Assert that the response sets a header named "Authorization" with value "Bearer abc123"
$this->assertHeaderEquals('Bearer abc123', $response, 'Authorization');

assertHeaderMatchesRegex

// Assert that the response sets a header named "Authorization" with a value that passes the regex
$this->assertHeaderMatchesRegex('/^Bearer [a-z0-9]$/i', $response, 'Authorization');

assertParsedBodyEquals

// Assert that the response body, after content negotiation, equals a value
$this->assertParsedBodyEquals(new User('Dave'), $response);

assertParsedBodyPassesCallback

// Assert that the response body, after content negotiation, passes a callback
$this->assertParsedBodyPassesCallback($response, User::class, fn ($user) => $user->name === 'Dave');

assertStatusCodeEquals

// Assert that the response status code equals a value
$this->assertStatusCodeEquals(200, $response);