Search code examples
phplaraveltestingguzzlelaravel-testing

Laravel mock multiple Guzzle endpoints


I'm using Laravel 6 and trying to test an endpoint. The endpoint is making 2 requests to external API's (from mollie). Currently I mock it like this:

Abstract BaseMollieEndpointTest

<?php

namespace Tests;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Mollie\Api\MollieApiClient;

abstract class BaseMollieEndpointTest extends TestCase
{
    /**
     * @var Client|\PHPUnit_Framework_MockObject_MockObject
     */
    protected $guzzleClient;

    /**
     * @var MollieApiClient
     */
    protected $apiClient;

    protected function mockApiCall(Response $response)
    {
        $this->guzzleClient = $this->createMock(Client::class);

        $this->apiClient = new MollieApiClient($this->guzzleClient);

        $this->apiClient->setApiKey('test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM');

        $this->guzzleClient
            ->expects($this->once())
            ->method('send')
            ->with($this->isInstanceOf(Request::class))
            ->willReturnCallback(function (Request $request) use ($response) {
                return $response;
            });
    }
}

All my tests extend from that ^ abstract class. And I implement it like this:

public function test()
{
    $this->mockApiCall(
        new Response(
            200,
            [],
            '{
              "response": "here is the response",
            }'
        )
    );

    Mollie::shouldReceive('api')
        ->once()
        ->andReturn(new MollieApiWrapper($this->app['config'], $this->apiClient));

    dd(Mollie::api()->customers()->get('238u3n'));
}

This is working. But the problem is when I need to mock another requests in the same api call I get same result back.

So how can I make sure I can mock 2 responses (instead of 1) and give it back for a specific url?


Solution

  • Take a look at great Guzzler library for mocking HTTP calls, and also at MockHandler with history middleware.

    Answering your particular question, with Guzzler it could be as simple as:

    $this->guzzler->expects($this->exactly(2))
        ->endpoint("/send", "POST")
        ->willRespond($response)
        ->willRespond(new Response(409));