Overview:
I have come across this question many times from people that how to test rest api using selenium webdriver. You could see many related questions in StackOverflow.com. People who are new to test automation sometimes do not understand that Selenium is only for automating the web based applications. However if you would like to do some data setup / data clean up for your UI tests using Selenium, then there are ways to do that by including some additional libraries. That is what we are going to see in this article.
If you need to test only APIs, then I would suggest you to check this.
So, In this article, lets see how to include REST API related testing in your existing selenium framework.
Udemy – Courses:
Checkout my udemy courses with max discount here. Use this coupon code OCT_2020_1
Problems With UI Testing:
- Usually UI is slow (This is because – Your browser first sends a request to a server for some information. As soon as it gets the required data, it might take some time processing the data and display them in a table / appropriate format by downloading images and applying the styles etc. So you have to wait for all these process to complete before interacting with the application)
- As it is slow, it is time consuming
- Same set of tests might have to be repeated for a different browser testing
- Browsers are separate process from your selenium scripts. So synchronization is always an issue.
- UI tests have a lot of dependencies like browsers / versions / grid / drivers etc
So, It does not mean that we should always do API level testing and release the product. We should try to do the API level testing as much as possible. We could have very minimal coverage for UI testing.
REST API Testing:
REST API testing is not very difficult compared to selenium web driver UI testing. Most of the APIs should be one of GET / POST / PUT / PATCH / DELETE requests.
- GET is used to get information from the back end to show in the UI
- POST is used to add new information into the back end.
- PUT is used to update / replace any existing information.
- PATCH is for partial update
- DELETE is used to delete the information from the back end.
If your aim is to do exhaustive testing on your REST APIs, I would suggest you to take a look at JMeter. You could check below articles on REST API testing using JMeter.
- JMeter – How To Test REST API / MicroServices
- JMeter – REST API Testing – A Complete Data-Driven Approach
- MicroServices – Contract Testing
Assuming you use a framework like testNG/Junit and do application UI testing using Selenium – now would like to include APIs as well in the same framework – may be for quick data setup or assertion etc, lets see how it can be done in this article.
Dependencies:
I have added below maven dependencies.
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.jtwig</groupId>
<artifactId>jtwig-core</artifactId>
<version>5.87.0.RELEASE</version>
</dependency>
- Unirest is a simple lightweight – fluent style HTTP request library
- JTwig is a very simple template engine
Sample Application:
I am going to consider this application for our testing. It has rest api to list the available contacts, to add / edit / delete contacts. It has also a nice UI built using Angular. You could clone and get that setup up and running in your local to place with that.
As soon as the above application launches, it makes the API GET request to get the list of contacts to display the data in the application.
Getting Contacts:
When you access the home page of the application, it lists all the contacts available.
If you monitor the network calls in the chrome-network, you could see some API GET request sent to fetch the list of contacts.
- If you are not sure where to check, press F12 when you are on the page in Chrome. Chrome DevTools will appear.
- Check Headers section for the api url
https://localhost:4200/api/contacts?q=
You could see some JSON response in the below format.
[
{
"id":"123",
"name":"Guru",
"email":"guru@gmail.com",
"thumbnail":"guru.jpg",
"phone":{
"mobile":111,
"work":222
},
"friends":[],
"numbers":[]
}
]
You could play with the application by adding a contact, modifying a contact, deleting a contact etc and monitor the network calls to get some idea. You could see above said GET / POST / PUT / DELETE requests.
GET Request:
As soon as the application launches, it makes the API GET request to get the list of contacts to display the data in the application.
You could make the above GET request yourself using Unirest as shown here.
String searchQueryApi = "https://localhost:4200/api/contacts?q=";
JsonNode body = Unirest.get(searchQueryApi)
.asJson()
.getBody();
System.out.println(body); // gives the full json response
System.out.println(body.length); // gives the no of items
This could be used to make simple assertions in the test framework. For example, below sample code confirms that all the data in the API response are displayed in the UI.
driver.get("http://localhost:4200");
List<WebElements> contacts = driver.findElements(By.tagName("tr"));
assert.equals(contacts.size(), body.length);
POST Request:
Whenever we try to add a new contact, a request JSON in the below format is sent!
{
"name": "guru",
"email": "guru@gmail.com",
"thumbnail": "",
"phone": {
"work": "",
"mobile": ""
},
"numbers": "[]",
"friends": "[]"
}
If your aim is to send the request yourself, then you might not want to hard code any value here in the JSON file. This is where we would use the JTwig template engine.
First, I create below template.
{
"name": "{{name}}",
"email": "{{email}}",
"thumbnail": "",
"phone": {
"work": "",
"mobile": ""
},
"numbers": "[]",
"friends": "[]"
}
I save the above JSON in a file called ‘contact.json‘. Now I could read the template and replace the values at run time as shown here.
JtwigTemplate template = JtwigTemplate.classpathTemplate("contact.json");
JtwigModel model = JtwigModel.newModel()
.with("name", "guru")
.with("email", "guru@gmail.com");
template.render(model); //gives the json in the above format by replacing the template expressions
Now we could use Unirest to send the above JSON to create new contact in the application.
String postApi = "https://localhost:4200/api/contacts";
Unirest.post(postApi)
.header("accept", "application/json")
.header("Content-Type", "application/json")
.body(template.render(model))
.asJson();
Using this approach you could add contacts quickly in the application.
Lets assume, the page could show max only 50 contacts. You need to click on the pagination links to see more contacts. But in your local / QA environment, when you start a fresh application, you might not have enough contacts to test functionality.
If your page object exposes a method to add a contact, you need to call more than 50 times. Adding contact via UI could be very time consuming. Due to synchronization issue, it could fail any moment. You need to handle the situation also – like in case of failure re-try or exit by marking the test failed etc.
With APIs, you could easily modify your page object as shown here. Now you could use this for data set up etc. It should be much faster than the UI approach and less error prone.
class ContactsPage{
//all find bys
//methods for interacting with web elements
public void addContacts(int numberOfContacts){
String postApi = "https://localhost:4200/api/contacts";
for(int i = 0; i<numberOfContacts; i++){
Unirest.post(postApi)
.header("accept", "application/json")
.header("Content-Type", "application/json")
.body(template.render(model))
.asJson();
}
}
}
Unirest can be easily used inside your page object as well as shown in the above example.
Edit Request:
To edit a contact, we need to send a PUT request as shown here.
String editApi = "https://localhost:4200/api/contacts/{contact_id}";
JtwigModel model = JtwigModel.newModel()
.with("name", "guru")
.with("email", "guru123@gmail.com");
Unirest.put(editApi)
.routeParam("contact_id", "125432")
.header("accept", "application/json")
.header("Content-Type", "application/json")
.body(template.render(model))
.asJson();
It edits the contacts email id.
Delete Request:
This is even more simpler as shown here.
String editApi = "https://localhost:4200/api/contacts/{contact_id}";
Unirest.delete(editApi)
.routeParam("contact_id", "1530237572905")
.asJson();
We could make use of this API to clean all the test data we had inserted as part of our test.
public class ContactsPageTest{
private String editApi = "https://localhost:4200/api/contacts/{contact_id}";
@Test
public void someUItest1(){
//
}
@Test
public void someUItest2(){
//
}
@AfterTest
public void teardown(){
for(String contactid: listOfContacts){
Unirest.delete(editApi)
.routeParam("contact_id", contactid)
.asJson();
}
}
}
Summary:
By using Unirest in your existing test framework / page objects, you could interact with the application REST APIs and you could also make use of those APIs for a quick data setup in your application for a quick functionality validation.
As you had seen the examples above, whenever possible, try to make use of the application APIs for your testing. I would suggest you to take a look at these approaches as well for exhaustive coverage for your APIs testing.
- JMeter – How To Test REST API / MicroServices
- JMeter – REST API Testing – A Complete Data-Driven Approach
- MicroServices – Contract Testing
Happy Testing & Subscribe 🙂
Thank you Vinoth for posting this and this is going to be useful for some many people I believe. If you have this kind of capabiility in your selenium framework , you can always combine both UI and the APIs which are available for your application, and take the adavantage of both. Some time you may not have to really do all the things from the UI itself and can use available APIs to quickly create / verify data from the application. That would speed up the overall execution of the test and help in reducing flakiness of test as well.. Thank you again for posting this and poeple aware of different open source techinques available for us 🙂
Hi, Good article.
But I can not see much difference between Restassure and Unirest. Please let me know if I am missing on anything to get difference between these two frameworks.
If you are already using rest-assured, then you should be good. rest-assured is a BDD style framework for testing APIs. Unirest is very simple & lightweight library compared to rest-assured which just sends the request and gives you the response. It is easy to mix with existing selenium scripts & page objects
The RESTool is running on port:4200 on my Windows 10. The url for contacts is http://localhost:4200/#/contacts. But you are referring to https://localhost:3000/api/contacts?q=. That page cannot be opened. Was that mistype from your side?
Port can be modified. I have updated the ‘Getting Contacts’ section. check once again for accessing the api details. In your case, you should be able to access here. https://localhost:4200/api/contacts?q=
With this url https://localhost:4200/api/contacts?q=, I’m getting this site can’t be reached. Please verify. As I wrote, I can see the RESTool contacts only at http://localhost:4200/#/contacts.
Please use this link – https://restool-sample-app.herokuapp.com/#/contacts
Thank you, Vinoth. That link works!
Extremely helpful! Thanks for sharing. It would be good to re-organize. More people would be interested if the blog was restructured as more organized, web-site instead.
Thank you a lot!
What if I want to use an integer value in the json ? How would I then go about it… ?
You can go with {{ }} expression. It does not have to be String. JTwigModel accepts an object