Search code examples
phptddphpspec

Testing API wrapper with phpspec


I'm trying to create a wrapper for an API class using TDD with phpspec.

I've written a Client class which deals with requesting/retrieving data from a REST API which is then mapped to of one several Entity classes, so it behaves like an ORM.

I'm a bit stuck now I've come to test and extend the application with TDD. As the Client is a dependency of the entity classes (so that they can request their own child objects), I'm struggling with mocking this.

For example, here's what one of the entities, Comic.php, might look like:

class Comic {

  protected $client;

  public $id;

  public function __construct(Client $client)
  {
    $this->client = $client;
  }

  public function getCharacters()
  {
    // just an example, this would return an array of Character objects
    return $this->client->request("comic/{$this->id}/characters");
  }

}

And for the sake of brevity here's what a simplified down version of Client.php looks like:

class Client {

  public function __construct($publicKey, $privateKey)
  {
    // make token from $publicKey, $privateKey
  }

  public function request($endpoint)
  {
    // use token for cURL request to endpoint and return data
  }

}

So how might a test on ComicSpec.php for it_gets_all_characters() look, as an example?

Hope this makes sense, can provide more info if needed.

Thanks for taking a look.


Solution

  • I'm not sure it_gets_all_characters would be a thing you test in ComicSpec since getting all characters doesn't look like one of Comic responsibilities. Right?

    What Comic must do (its responsibility) is to call the client and trust on it to retrieve the characters. So in ComicSpec you should mock Client and test that Comic calls it with the correct message and parameters:

    In ComicSpec:

    function it_gets_all_characters(Client $client)
    {
        $this->beConstructedWith($client);
    
        $client->request(Argument::any())->shouldBeCalled();
    
        $this->getCharacters();
    }
    

    Notice you haven't tested the API calling, so you also need a ClientSpec to do that. If you use curl I think it's basically impossible to test it (without actually calling the service), but maybe you can use Guzzle. In ClientSpec you would mock the HttpClient and test that Client calls it with the correct message and parameters.

    I hope this helps!