0

I'm trying to build a class that queries an external API. Each method that corresponds to an endpoint makes a call to a 'master call' method responsible for actually sending a request to the API.

For example:

// $this->http is Guzzlehttp\Client 5.3

public function call($httpMethod, $endpoint, array $parameters = [])
{
    $parameters = array_merge($parameters, [
        'headers' => [
            'something' => 'something'
        ]
    ]);

    $request = $this->http->createRequest($httpMethod, $this->baseUrl . $endpoint, $parameters);

    return $this->http->send($request);
}

public function getAll()
{
    return $this->call('GET', 'all');
}

What I'm I supposed to mock? Should I use willBeCalled() and/or willReturn() on the http client's createRequest() and send() methods?

When I mock send(), it says: Argument 1 passed to Double\GuzzleHttp\Client\P2::send() must implement interface GuzzleHttp\Message\RequestInterface, null given and I'm not sure how to provide a fake for that, because creating a dummy for that interface requires me to implement 30 methods on that class.

Here's the test right now:

function it_lists_all_the_things(HttpClient $http)
{
    $this->call('GET', 'all')->willBeCalled();
    $http->createRequest()->willBeCalled();
    $http->send()->willReturn(['foo' => 'bar']);

    $this->getAll()->shouldHaveKeyWithValue('foo', 'bar'); 
}
johnRivs
  • 135
  • 2
  • 4
  • 19

1 Answers1

1

You should mock the behaviour, something like this:

public function let(Client $http)
{
    $this->beConstructedWith($http, 'http://someurl.com/');
}

function it_calls_api_correctly(Client $http, Request $request)
{
    $parameters = array_merge([
        'headers' => [
            'something' => 'something'
        ]
    ]);

    $http->createRequest('GET', 'http://someurl.com/all', $parameters)->shouldBeCalled()->willReturn($request);

    $http->send($request)->shouldBeCalled();

    $this->getAll();
}
gvf
  • 1,039
  • 7
  • 6
  • I think I tried something similar. The problem is, if I typehint `GuzzleHttp\Message\RequestInterface $request` and pass it to `send()`, it's gonna say "you need to implement a bajillion methods". Should I create a dummy class below the spec class that implements all those methods? – johnRivs Jun 20 '15 at 16:24
  • I tried that approach, and now I need one more thing. In my code, I need to return `$this->http->send($request)->json()` but phpspec's telling me it can't find it. At the moment, I have `$http->send($request)->json()->shouldBeCalled()`. – johnRivs Jun 20 '15 at 19:26
  • Yo need to mock what `send` returns: `$this->http->send($request)->shouldBeCalled()->willReturn($whatever)`, and `$whatever->json()->shouldBeCalled()` – gvf Jun 20 '15 at 20:40