HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Unit testing code that calls RESTful API

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
callsthattestingrestfulcodeapiunit

Problem

I'm writing a library which calls a RESTful API and then performs some work on the data.

I've architected my code like this:

I have a class (let's call it APIRequestor) that initiates a call to the API via an injected HTTPRequestor library (which basically wraps a cURL request). That class, after retrieving the response, will perform some operations on that data and then return an APIResult object to the caller.

In order to test the APIRequestor, I created a HTTPRequestorMock which extends HTTPRequestor that, rather than wrapping a cURL request, it simply reads a result from a file I have on disk that way I can test different scenarios.

Below is the code for the APIRequestor object:

HTTPLibrary = new HTTPRequestorMock();
        return $requestor;
    }

    public function testResponseIDsNoResults() {
        $requestor = $this->getMockedRequestor();
        $requestor->HTTPLibrary->overrideFilepath = "./mock_assets/ResponseIDsNoResults.xml";
        $responseIDs = $requestor->getResponseIDsSinceResponseID(0);
        $this->assertTrue(count($responseIDs) === 0, "More than zero results returned.");
    }

}


  • Is this a good design?



  • Can I improve this design in order to make future additions more testable?



  • Is this the common practice for removing a dependency on an external server for the sake of my unit tests?

Solution

Yes, it looks like a reasonable design and approach.

At the nit-pick level getMockedRequestor should be private or protected, to document that it is a helper for the tests. Also, if every test is going to be calling it, some people might move that code into setUp(). But that only saves one line ($requestor = $this->getMockedRequestor();) in each unit test, so I'd keep it where it is: I like to avoid using member variables, but that is personal preference.

You could use the phpUnit mock interface, but you don't have to. It gives you some very useful things, such as when you say you expect a function to be called once with "Hello World":

$requestor->expects($this->once())
  ->method('afunction')
  ->with($this->equalTo('Hello World'));


Then it will not only complain if afunction() never gets called, but also if it gets called twice.

But structure like this also brings restrictions. Have a poke around some of the phpunit mock questions on StackOverflow to see if you will hit them.

Code Snippets

$requestor->expects($this->once())
  ->method('afunction')
  ->with($this->equalTo('Hello World'));

Context

StackExchange Code Review Q#15201, answer score: 4

Revisions (0)

No revisions yet.