Introduction
Testing an application means more than just clicking around until something breaks or trying different inputs until something isn't working right.
While this is a good way to find anything that might break on the user facing side of the application, due to misuse - what is being neglected is the fact that APIs which process your requests aren't being adequately tested this way.
What is an API?
First and foremost, to know how to test an API, you must know what an API is. In very broad terms, it allows two pieces of software to interact with one another, in order to access data, or a part of the other program's functionality.
It allows you to send an HTTP Request in order to get an HTTP Response, in more technical terms. This is practically the backbone of the Internet and how we interact with applications/how applications interact with each other.
A more specific example would be - your application has a GUI where you can enter a movie title, and it returns results (response), based on what you wrote (request). You can choose to do this using an API, which simply 'fetches' this data from the server.
Another example would be - you want to make a payment to someone (request), and the receiver's data is sent to the server based on your input, again via an API. This time around, the response would be that you successfully (or unsuccessfully) completed the payment.
Why Use Postman?
While there are other tools available (SoapUI, Katalon, Tricentis), Postman stands out as one of the more beginner friendly tools you can use to start testing your API.
One of the biggest reasons for this is - you don't have to learn a new language and will only ever need JavaScript, regardless of the language which the API is written in. It allows you to very quickly send requests to the API you're testing.
Some of the other reasons are:
- You can make automated test collections relatively easily and quickly
- You can also make reusable tests without needing to run them automatically, or integrate them with anything
- Test collections can be exported and run via command line with its Node.js package, newman, which in turn can be integrated with a CI/CD system
- Can be run on Mac, Windows, Chrome Apps and Linux
- Very easy to share your test collections, even when they are work-in-progress
- Interface allows importing endpoints from Swagger or RAML files, as a starting point for tests, which shortens the amount of time needed to make a request
- Developers can use it as a quick way to test the endpoint while its still a work-in-progress, especially combined with the previous bullet-point
- Allows storing variables from responses for future use
- Allows using different sets of variables to test different setups and dynamic responses
- Allows use of files for Data Driven Testing
- Has a console that is based on the one Google Chrome has, allowing you to easily debug while implementing tests
- Free (with premium features)
- Saves data (on account) across devices
Cons of Postman
While you can use files for Data Driven Testing, you have to go the extra mile to design your tests to work without the use of one. Postman will return errors when it can't read a file, which you can't do when manually running a request - which is mostly what you will do when implementing a test.
Also, while it is a pro that it is free, it's premium features lock monitoring and automated calls without any external programs behind a fee. This can be countered with an internal system or pipeline, like mentioned with newman.
Using Postman
Installing Postman
Installing Postman is as simple as going to their website, downloading it and running the .exe
file. Make sure you download the correct version, but it generally already selects the one based on your system:
Starting Postman
After you've installed it, simply launch Postman and you will be met with the following UI:
Here, you can create an account. It is not necessary but it's advised to make one, since the account allows you to save your data across devices simply by working in the app.
If you ever do make an account, chances are you will delete everything you worked on up until that point. In case you just want to get into the meat of it as quickly as possible, click Skip signing in and take me straight to the app.
After making an account (or not), you'll be greeted with the main page:
Sending Requests
First things first, you have to make a crucial decision - Dark mode or Light mode? I prefer Dark mode, which is what I'll be using for the remainder of this article:
Once you've decided, selecting either a) or b) will create a new tab:
Now, the way you interact with an API is by calling it's URL, or in other terms, invoking the endpoint. This means you will contact something that is either publicly exposed, or something you've started locally.
To keep it simple, we will use something that is publicly available. This website allows you to filter anime based on your search term:
It does this by invoking the endpoint (sending your request) and returning a web page with the results (showing the response).
Note: Depending on the search algorithm websites use, they might return terms that vaguely match the search term. This might affect your results later in the article.
You can use your own search term, or simply copy one created in the example image:https://api.jikan.moe/v3/search/anime?q=aggretsuko&limit=16
Navigating back to Postman, we can enter the URL into the designated field:
The Params section is automatically filled with parameters found in the provided URL. This means that the URL is constructed with two values that will affect what you get as a result from sending this request.
Now, let's send the request:
The response is in the JSON format, which is pretty standard for most API's nowadays. If you look back at the website, you got a list of items that matched your search term, and this is in fact the same list, with the same items.
You can see that there are multiple keys that have the same name, and each key has a value, which is different (but doesn't have to be) than the previous item.
Let's take a look at this part of the JSON:
{
"mal_id": 12391,
"url": "https://myanimelist.net/anime/12391/Mouretsu_Atarou_1990",
"image_url": "https://cdn.myanimelist.net/images/anime/12/34815.jpg?s=18636fcc6bfe9368cbd3e021d6aca915",
"title": "Mouretsu Atarou (1990)",
"airing": false,
"synopsis": "Batsugoro was the owner of a grocery store, Yaobatsu. When he tried to take a balloon hanged caught on the branch for a little child, he fell on to the ground to die. His son, Ataro, succeeded to the...",
"type": "TV",
"episodes": 34,
"score": 0,
"start_date": "1990-04-21T00:00:00+00:00",
"end_date": "1990-12-22T00:00:00+00:00",
"members": 231,
"rated": "G"
},
{
"mal_id": 34016,
"url": "https://myanimelist.net/anime/34016/Hatsukoi_Monster__Mou_Chotto_dake_Tsuzukunja",
"image_url": "https://cdn.myanimelist.net/images/anime/2/81905.jpg?s=b2c7e247db555c7477f319ace2d927c8",
"title": "Hatsukoi Monster: Mou Chotto dake Tsuzukunja",
"airing": false,
"synopsis": "Unaired episode bundled with the eight manga volume.",
"type": "OVA",
"episodes": 1,
"score": 6.27,
"start_date": "2017-02-07T00:00:00+00:00",
"end_date": "2017-02-07T00:00:00+00:00",
"members": 5594,
"rated": "PG-13"
}
All of the information returned by the API is present here, including the links to the images used.
Now, you might ask yourself:
Why bother with this, when you can simply... go to the website and perform a search there?
Well, in the development process, sometimes you will have a team of developers where one part of the team is developing the back-end (API) while there is still no front-end (GUI) to be seen. In this stage it is very handy to test the API as soon as it is developed, before it is even integrated into anything else, and return feedback in case it's not up to the documentation, or there's some sort of error.
Another thing you might notice is, there's a lot of data that's not being used on the website. The reasoning here is - the developer of this website probably didn't need this information, but the API he's using offers it - because it is required for the developer of this API. Sometimes, there's even data that's simply required elsewhere, and/or it's not needed to be seen on the UI at all.
You might want to save this request in case you want to use it later, and the way you do this is simply clicking Ctrl+S
on your keyboard, or clicking the Save button next to the Send button:
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Select the the + Create Collection button, because you need one to save the request in:
And save the request:
You can access your collections and requests through the Collections tab:
Clicking on the request will open it up in the new tab.
Creating Assertions
Under the "Tests" tab, you'll be greeted with an editor for your code:
Now, let's enter a really simple test which asserts that we'll receive a status code of 200
:
pm.test("Status code is 200", function() {
pm.response.to.have.status(200);
});
As you can see on the right, there are some snippets, which can be quite useful while you get acquainted with them. These can be used as macros to avoid writing some really common code all the time.
Clicking Send again, you will now have a test attached to your request. This one in particular asserts the status code to be 200 OK
.
This is used to check if you successfully completed the requested action (in this case, getting some data). In case something went wrong, you would get one of the error codes, such as 404 not found
, 400 bad request
, etc.
Sending the request, we're greeted with a passed test case:
Now let's try checking if both of the titles contain the word "seven" in them:
// Get the response
let responseBody = pm.response.json();
// Get the title of the first few elements
let firstTitle = responseBody.results[].title;
let secondTitle = responseBody.results[].title;
pm.test("Title of the first item in response contains 'seven'", function() {
pm.expect(firstTitle.toLowerCase()).to.include("seven");
});
pm.test("Title of the second item in response contains 'seven'", function() {
pm.expect(secondTitle.toLowerCase()).to.include("seven");
});
Since .to.include()
is case-sensitive, we use the .toLowerCase()
function in the chain, otherwise the test would likely falsely fail.
Running this piece of code will return us:
Now, imagine having a list of more than 10 items you wanted to check... it would be insane to copy paste the code 10 times, and sometimes you can realistically get more than hundreds of results, so let's introduce a simple for-each
loop.
First though, let's change the q
param to something more mainstream like Naruto
and the limit
param to 10
:
pm.test("Status code is 200", function() {
pm.response.to.have.status(200);
});
let responseBody = pm.response.json();
let results = responseBody.results;
results.forEach(function(result, i) {
pm.test(`Title of item number ${i + 1} in response contains 'naruto'`, function() {
pm.expect(result.title.toLowerCase()).to.include("naruto");
});
});
In function(result, i)
each of the items is automatically assigned to result
on each pass, and i
is the last parameter, so JavaScript automatically assigns it as an internal counter. This is why we use ${i + 1}
to count which item we're testing. If we didn't add a counter to the test name itself, Postman would render it with one test. Try removing it to see for yourself.
As you can see, much less code, and much more tests!
As an exercise, try adding another parameter called type
and set its value to TV
, then assert that every item has its key
set to TV
. Remember that it might return a term that vaguely matches the term, in case you see a test fail.
Introducing Variables
For further capability of Postman, let's introduce variables into the mix. I won't go into global variables, environment variables are more useful for starters:
Let's add an environment variable such as naruto-10
with the q
and limit
set to naruto
and 10
respectively:
Change your URL so that the parameters aren't hard-coded, but rather can be set to any variable we define afterwards:
https://api.jikan.moe/v3/search/anime?q={{q}}&limit={{limit}}
As you can see, we added q={{q}}&limit={{limit}}
instead of a fixed value. the {{}}
with something in-between is how Postman knows it's looking for a variable. You will notice it will be red, and this is because we haven't selected an environment, so Postman is telling us it can't find the variable:
And now, we can change our code to use the environment variables by calling the environment
object:
let responseBody = pm.response.json();
let results = responseBody.results;
results.forEach(function(result, i) {
pm.test(`Title of item number ${i + 1} in response contains ${environment.q}`, function() {
pm.expect(result.title.toLowerCase()).to.include(environment.q);
});
});
Sending the request in this state should also return us several passed tests:
Conclusion
Postman stands out as one of the more beginner friendly tools you can use to start testing your APIs. One of the biggest reasons for this is - you don't have to learn a new language and will only ever need JavaScript, regardless of the language which the API is written in.
If you want to test yourself and are currently on a project, try finding out if there's any API you can access, and potentially call from Postman. If not, there's a lot of public APIs similar to the one used in this article.