How we test external APIs

Without slowing down our normal test suite

Joel Clermont
Joel Clermont
2024-06-03

When you're writing tests that involve third-party services, it's useful to mock out those services, so you're not constantly hitting live APIs in your tests.

Not only does this keep your tests running faster, it also saves you from incurring upstream charges or filling a sandbox account with test data.

That being said, if you only interact with mocks in your tests, how do you know your code actually works with the live API? How do you detect possible API drift over time?

In our normal feature tests we block all API calls with Http::preventStrayRequests(). But then we have an extra folder tests/External, where we place the subset of our tests that should hit a live API.

Our normal phpunit.xml config file does not include the external tests, so when we just run phpunit it will not run those tests by default.

We then have a phpunit-external.xml config file, which is pretty much identical to our main config, except it only defines the External test suite:

<testsuites>
    <testsuite name="External">
        <directory>./tests/External</directory>
    </testsuite>
</testsuites>

Now, we can have two different test scripts in our composer.json, which we call depending on whether we want to run external tests our not:

{
    "scripts": {
        "test": [
            "phpunit"
        ],
        "test-external": [
            "phpunit --configuration=phpunit-external.xml"
        ]
    }
}

We have achieved the goal of fast tests and still being able to detect API drift.

Here to help,

Joel

P.S. Have you seen Ash Allen's excellent book on Laravel APIs?

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼

Level up your Laravel skills!

Each 2-minute email has real-world advice you can use.