Get started with 33% off your first certification using code: 33OFFNEW

How to test external API responses in Laravel

4 min read
Published on 18th April 2023

Testing is a crucial aspect of any application's development process. In Laravel, it's easy to write tests for various parts of your application, including API interactions. When testing APIs, you might need to fake responses to ensure your tests are fast, reliable, and independent of external factors. In this blog post, we'll dive into using Laravel's Http::fake method to fake API responses during testing, complete with code examples to help you get started.

While Laravel has great documentation, its docs on HTTP tests don't go into much detail on the method below.

Setting up a Laravel Test

Before diving into Http::fake, let's quickly set up a test in Laravel. If you haven't already, create a new Laravel project using Composer:

composer create-project --prefer-dist laravel/laravel my_project

Now, navigate to your project's root directory (cd my_project) and create a new test class using the Artisan command:

php artisan make:test HttpFakeTest

We're using the traditional PHPUnit approach here to create a Feature test, but you can do something similar with Pest by adding --pest. The actual test will differ with Pest though, so we'll stick with PHPUnit for this post. If you're interested in testing with Pest check out their section on Mocking, although it's not as clear as it could be on how to mock HTTP requests.

This command will generate a new test file named HttpFakeTest.php in the tests/Feature directory. Open this file and add the necessary imports at the top:

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

Using Http::fake to Fake API Responses

Now that we have our test class set up, let's explore how to use Http::fake to fake API responses.

Suppose you have a service class called WeatherService that fetches weather data from an external API. Here's a simplified version of the WeatherService class:

namespace App\Services;

use Illuminate\Support\Facades\Http;

class WeatherService
{
    public function getWeatherData($city)
    {
        $response = Http::get("https://api.example.com/weather?city={$city}");

        return $response->json();
    }
}

To test the getWeatherData method without making actual API calls, you can use Http::fake to fake the response from the external API.

Here's an example of a test that uses Http::fake to fake the weather API's response:

/** @test */
public function it_fakes_weather_api_response()
{
    // Fake the API response
    Http::fake([
        'api.example.com/weather*' => Http::response([
            'city' => 'New York',
            'temperature' => 75,
            'conditions' => 'Sunny'
        ], 200),
    ]);

    // Instantiate the WeatherService class
    $weatherService = new WeatherService();

    // Call the getWeatherData method with a sample city
    $response = $weatherService->getWeatherData('New York');

    // Assertions
    $this->assertSame('New York', $response['city']);
    $this->assertSame(75, $response['temperature']);
    $this->assertSame('Sunny', $response['conditions']);
}

In the test above, the Http::fake method is used to define the fake API response for any request made to the api.example.com/weather* endpoint. The Http::response method is then used to create a fake response object with the desired data and status code.

In essence, Http::fake instructs Laravel to intercept any outbound request to the endpoint you specify and instead response with the response you define.

When the getWeatherData method is called within the test, it will receive the fake response instead of making an actual API call, allowing you to test your application's behaviour based on different API responses.

Faking Specific Endpoints and Responses

In some cases, you may want to fake responses for specific endpoints or conditions. To achieve this, you can use Http::fake with a closure. The closure will receive the request object as an argument, allowing you to determine how to fake the response based on the request's properties.

For example, let's say you want to fake different responses depending on the city passed to the getWeatherData method. Here's how you can achieve this:

/** @test */
public function it_fakes_weather_api_response_based_on_city()
{
    // Fake the API response
    Http::fake(function ($request) {
        $url = $request->url();

        if (strpos($url, 'New York') !== false) {
            return Http::response([
                'city' => 'New York',
                'temperature' => 75,
                'conditions' => 'Sunny',
            ], 200);
        } elseif (strpos($url, 'London') !== false) {
            return Http::response([
                'city' => 'London',
                'temperature' => 55,
                'conditions' => 'Cloudy',
            ], 200);
        }

        return Http::response([], 404);
    });

    // Instantiate the WeatherService class
    $weatherService = new WeatherService();

    // Call the getWeatherData method with different cities
    $responseNewYork = $weatherService->getWeatherData('New York');
    $responseLondon = $weatherService->getWeatherData('London');

    // Assertions for New York
    $this->assertSame('New York', $responseNewYork['city']);
    $this->assertSame(75, $responseNewYork['temperature']);
    $this->assertSame('Sunny', $responseNewYork['conditions']);

    // Assertions for London
    $this->assertSame('London', $responseLondon['city']);
    $this->assertSame(55, $responseLondon['temperature']);
    $this->assertSame('Cloudy', $responseLondon['conditions']);
}

In this test, we use a closure with Http::fake to inspect the request's URL and return a different fake response based on the city. This approach allows you to create more dynamic and context-aware fakes for your tests.

Summary

Faking API responses is an essential part of testing applications that interact with external APIs. Laravel's Http::fake method makes it easy to fake responses for your tests, ensuring they remain fast, reliable, and independent of external factors.

By using Http::fake, you can create simple or complex fake responses for your tests, allowing you to test your application's behaviour in various scenarios without making actual API calls. With this powerful tool at your disposal, you can write more robust and comprehensive tests for your Laravel applications.

There are a number of commonly used Facades within Laravel that can work in this way, the Http client is just one of them. Another commonly used, tested and faked Facade within Laravel is the Storage Facade. It too has a fake method which can be used in a similar fashion.