Chapter 9: Testing APIs
Design and Build Great Web APIs — by Mike Amundsen
The Goals of API Testing
First and foremost, the goal of API testing is to do just that — test the interface. That means you need to test each URL (or “endpoint”) in the API, including any possible input parameters. You also need to confirm the responses to those endpoint requests. You need to make sure each promised endpoint exists and accepts the inputs and produces the outputs expected.
Test the APIs Behavior
In addition to testing the interface, you also need to make sure the API behaves the way you’d expect from reading the Application-Level Profile Semantics (ALPS) description and the OpenAPI Specification (OAS) documents. For example, an API might have a rule that each request for a credit rating will return a value between 1 and 10. If the API returns a value 0 or 13, thats unexpected behavior.
Another API might have a rule that you cant create two records with the same companyName value. That means any attempt to break that rule results in an API behavior of refusing to write the duplicate record and returning an HTTP 400 Bad Request response.
Testing for expected. (or unexpected) behavior is critical to proper API testing. And there’s an entire practice and set of tools around this approach, known as behavior-driven development, or BDD. This pattern was created to make the whole process of thinking and implementing testing more accessible to audience that goes beyond programmers.
TDD or test-driven development can be described as a code-centric practice of improving the quality of the code you’re writing, while BDD is the practice to improve the behavior of the system you’re building.
BDD is an “outside-in” methodology. When we’re working with APIs, the only target we have for testing is the “outside” — the interface itself.
Test Both Happy and Sad Paths
A common approach to testing is to confirm that the interface is doing what it’s designed to do. For example, I should be able to get a list of customers, filter that list using selected properties, add new customers, edit them and maybe even remove them from storage. Logically I should be able to turn these expectations into simple tests and execute those tests to “prove” that my expectations are met.
http://localhost:8181/list/
http://localhost:8181/filter?status=active
http://localhost:8181/ -X POST -d \
id=q1w2e3r4&status=pending&email=test@example.org
http://localhost:8181/status/q1w2e3r4 -X PATCH -d status=active
http://localhost:8181/q1w2e3r4 -X DELETE
Each of these requests represents a test of one of my expectations. Essentially, I expect all of these requests to succeed. In HTTP API lingo, I expect the server to return a 200 OK response along with the proper text body. These are examples of “happy path” tests. When they work, everyone is happy.
However, I have another important set of expectations about the customer API. I expect, for example, that the API won’t let me add a new customer record unless I supply all the required fields. I expect the API to prevent me from adding duplicate customer records. I expect it to validate the data qualities of each field to make sure I don’t save a string to a numeric field, or attempt to write an invalid string to an email field, and so forth. These are “sad path” tests. Using HTTP API–speak, they should return 400 Bad Request (or some other 4xx HTTP status code). It’s important to validate that your API prevents undesirable things from happening too.
For this reason, I always try to come up both “happy path” and “sad path” tests for my APIs. And that means I need to collect the tests in a set and then execute them in a consistent way.
Testing with SRTs
An easy way to start testing your API is to focus just on the interface itself with what I call simple request tests, or SRTs. SRTs are just what the name sounds like: a simple HTTP request you can run to validate that the minimal elements of the API are working as you would expect. And that’s how I use SRTs — to validate the API.
Here are a few examples of SRTs used for testing an API that supports managing people’s contact information:
# person api test requests
# 2020-02 mamund
http://localhost:8181/
http://localhost:8181/list/
http://localhost:8181/filter?status=active
http://localhost:8181/ -X POST -d \
id=q1w2e3r4&status=pending&email=test@example.org http://localhost:8181/q1w2e3r4 -X PUT -d \
givenName=Mike&familyName=Mork&telephone=123-456-7890
http://localhost:8181/status/q1w2e3r4 -X PATCH -d status=active
http://localhost:8181/q1w2e3r4 -X DELETE
# EOF
Because HTTP APIs rely on URLs, HTTP methods, and a few HTTP headers, tools like curl give you all the power you need to create a collection of SRTs that you can run against your API. You can do this while you’re implementing the API as a kind of quick validation of your progress as you write your API code. You can also use SRTs as a simple validator once you’ve released your APIs into production to make sure the deployed API works as expected.
SRTs are a good first step in validating your interface implementation, but this doesn’t qualify as real testing since we’re not yet focused on that all-important expected behavior. To do that, you need more powerful tools and a more in-depth approach. For that, I like to use a tool called Postman, which we’ll look at next.
Using Postman for API Testing
Postman is a platform for working with web APIs. Originally focused just on testing, the Postman platform now offers support for generating documentation, spinning up API mock servers, and even designing APIs.
You can explore more on Postman and the latest features in this link.