In testing web applications, the page object design pattern has become justifiably famous. Its job is classic data hiding: each such object encapsulates an HTML page.
When I began working on my first framework for testing a REST API, I asked myself how, if at all, this encapsulation principle applies there. And the immediately obvious answer is: the endpoint object.
Just as the page object encapsulates an HTML page, so does the endpoint object encapsulate a REST API endpoint. Each endpoint has its own encapsulating class.
Now an endpoint does not have a name, exactly, but it does have an HTTP method and a URL. I've used those to construct the endpoint class name.
Examples (from my framework for testing for GitHub's own REST API):
Method and URL | Endpoint Class Name | Effect |
---|---|---|
GET /labels |
GetLabels |
Get all labels. |
POST /labels |
PostLabels |
Create a label. |
GET /labels/:name |
GetLabelsName |
Get the named label. |
PATCH /labels/:name |
PatchLabelsName |
Update the named label. |
DELETE /labels/:name |
DeleteLabelsName |
Delete the named label. |
A test framework should make things simple for the tester, right? To that end, the methods in these objects accept and return actual Ruby Label
objects, not raw JSON. The methods transparently handle the transforms between JSON and those objects.
Each endpoint has four such methods. Using PatchLabels
as an example:
-
PatchLabels.call(client, label)
creates a label and returns the created label as aLabel
object. -
PatchLabels.call_and_return_payload(client, label)
does the same, but returns both theLabel
object and the raw JSON payload (in case the caller want to examine it). -
PatchLabels.verdict_call_and_verify_success(client, log, label)
creates a label and returns the created label as aLabel
object, also logging relevant verdicts. -
PatchLabels.verdict_aberrant(client, log)
accesses the endpoint with various error-causing aberrations, logging relevant verdicts, and returning nothing.
Voilà , the endpoint object!