This dependency will also transitively add the following libraries to the classpath:
jackson-annotations
jackson-core
In the below example, let us assume that we need to create a new Employee (POST Request) .To start with, we need to create POJO class of the JSON payload (EmployeeDetails). This POJO class should contain the data members corresponding to the JSON nodes and their corresponding getter and setter methods.
public class EmployeeDetails {
// private variables or data members of pojo class
private String name;
private double salary;
private int age;
// Getter and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Now that we have our POJO class we can start writing some REST Assured Serialization tests!
Let’s start with REST Assured Serialization with JSON. I want to send a POST request to my EmployeeDetails API that will add a new Employee to the database. I will send a POJO of the employee in the request body. This is what the code looks like in the test class:
@Test
public void createEmployee() {
// Create an object of POJO class
EmployeeDetails emp = new EmployeeDetails();
emp.setName("Vibha");
emp.setSalary(75000);
emp.setAge(30);
// Converting a Java class object to a JSON payload as string
ObjectMapper mapper = new ObjectMapper();
String employeePrettyJson = null;
try {
employeePrettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(emp);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("Request");
System.out.println(employeePrettyJson);
System.out.println("=========================================");
System.out.println("Response");
// GIVEN
given().baseUri("http://dummy.restapiexample.com/api").contentType(ContentType.JSON).body(emp)
// WHEN
.when().post("/v1/create")
// THEN
.then().assertThat().statusCode(200).body("data.name", equalTo("Vibha"))
.body("message", equalTo("Successfully! Record has been added.")).log().body();
}
}
If you want to see the structure of Request, then add the below in the test code.
ObjectMapper mapper = new ObjectMapper();
String employeePrettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(emp);
System.out.println(employeePrettyJson);
REST Assured Serialization with Jackson handled all the serialization work for us. Great! See this has become so simple with the help of Jackson API.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
We need to create an Employee class that contains private data members and corresponding getter and setter methods of these data members.
Below is an Employee Class with private data members, as well as the corresponding getter and setter methods of these data members. Every IDE provides a shortcut to create these getter and setter methods.
public class Employee {
// private variables or data members of POJO class
private String firstName;
private String lastName;
private int age;
private double salary;
private String designation;
private String contactNumber;
private String emailId;
// Getter and setter methods
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
}
Serialization – Serialization is a process where you convert an Instance of a Class (Object of a class) into a Byte Stream. Here, we are converting Employee class object to JSON Array representation or Object.
Deserialization – It is the reverse of serializing. In this process, we will read the Serialized byte stream from the file and convert it back into the Class instance representation. Here, we are converting a JSON Array to an Employee class object.
We are using Jackson API for Serialization and Deserialization. So, add the Jackson dependency to the project.
In this tutorial, I will explain the creation of JSON Object Payload with the help of POJO (Plain Old Java Object).
What is POJO?
POJO stands for Plain Old Java Object. It is a very simple object and it has no bound or we can say that it has no restrictions other than the Java language specification. Also, it does not require any classpath.
A big advantage of POJO is it increases the readability and reusability of our project code and developers find it easy when understanding the code. Also, POJO is easy to write and anyone can understand them easily.
Now let’s deep dive into some technical terms about the POJO. Below are a few points about the POJO are:
A POJO should not have to extend prespecified classes.
Secondly, a POJO should not have implemented any prespecified interface.
Lastly, POJO should not contain prespecified annotations
A POJO class can follow some rules for better usability. These rules are:-
Each variable should be declared as private just to restrict direct access.
Each variable which needs to be accessed outside class may have a getter or a setter or both methods. If value of a field is stored after some calculations then we must not have any setter method for that.
It Should have a default public constructor.
Can override toString(), hashcode and equals() methods.
POJO classes are extensively used for creating JSON and XML payloads for API.
In the below example, let me create a simple JSON with some nodes which is actually a 1:1 mapping i.e. each key has a single value, and the type of values is mixed.
Let us create variables in the POJO class now for the above JSON. Now, a class name Employee will be created with the private data members as mentioned in the above JSON. Since we have created all variables as private, then there should be a way to manipulate or retrieve these data. So we create the corresponding getter and setter methods for these data members.
It is very tedious to create getter and setter methods for all the data members for big JSON strings. Every IDE gives you a shortcut to generate getter and setter methods. Here, I am using Eclipse and creating these getter and setter methods.
Select all the data members and Right-click on the page. Then select Source and then select Generate Getter and Setter methods.
This opens a new screen as shown below.
You can select the data member for which you want to create the getter and setter method. I want to create the getter and setter methods for all the data members, so click on Select All and then click on the Generate Button. This will generate the getter and setter methods for all the data members.
Below is the sample code of the Employee table, which contains the data members needed for Employee JSON and their corresponding getter and setter methods.
public class Employee {
// private variables or data members of POJO class
private String firstName;
private String lastName;
private int age;
private double salary;
private String designation;
private String contactNumber;
private String emailId;
// Getter and setter methods
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
}
Using the above POJO class, you can create any number of custom Employee objects and each object can be converted into a JSON Object and Each JSON object can be parsed into Employee POJO.
We will create a JSON object from POJO and vice versa now, which is generally called serialization and deserialization using Jackson APIs.
Serialization – Serialization is a process where you convert an Instance of a Class (Object of a class) into a Byte Stream. Here, we are converting Employee class object to JSON representation or Object
Deserialization – It is the reverse of serializing. In this process, we will read the Serialized byte stream from the file and convert it back into the Class instance representation. Here, we are converting a JSON Object to an Employee class object.
We are using Jackson API for Serialization and Deserialization. So, add the Jackson dependency to the project.
ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects), or to and from a general-purpose JSON Tree Model (JsonNode), as well as related functionality for performing conversions. It is also highly customizable to work both with different styles of JSON content and to support more advanced object concepts such as polymorphism and object identity.
Now, let us create a Test Class to show Serialization.
public class EmployeeTest {
@Test
public void serializationTest() {
Employee employee = new Employee();
employee.setFirstName("Vibha");
employee.setLastName("Singh");
employee.setAge(30);
employee.setSalary(75000);
employee.setDesignation("Manager");
// Converting a Java class object to a JSON payload as string
ObjectMapper mapper = new ObjectMapper();
String employeeJson = mapper.writeValueAsString(employee);
String employeePrettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee);
System.out.println(employeeJson);
System.out.println(employeePrettyJson);
}
}try {
String employeeJson = mapper.writeValueAsString(employee);
System.out.println(employeeJson);
String employeePrettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee);
System.out.println(employeePrettyJson);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
Here, ObjectMapper from fasterxml.jackson.databind is used for Serialization.
writeValueAsString() is a method that can be used to serialize any Java value as a String.
writerWithDefaultPrettyPrinter() is used to pretty-print the JSON output. It is a Factory method for constructing ObjectWriter that will serialize objects using the default pretty printer for indentation.
I hope this has helped to clear your doubts regarding POJO and how to create JSON Object using POJO.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
In this tutorial, I will explain the Integration of Serenity BDD with Rest Assured for the testing of RestFul API.
What is Serenity BDD?
Serenity BDD is an open-source library that aims to make the idea of living documentation a reality.
What is Rest Assured?
Rest Assured is one of the most powerful libraries for testing RESTful API using Java language. Rest-Assured is a Java-based library that is used to test RESTful Web Services. This library behaves like a headless Client to access REST web services. The rest-Assured library also provides the ability to validate the HTTP Responses received from the server.
Pre-Requisite
Java 11 installed
Maven installed
Eclipse or IntelliJ installed
This framework consists of:
Java 11
Maven – 3.8.1
Serenity – 3.2.5
Serenity Rest Assured – 3.2.5
Rest Assured – 5.1.1
JUnit – 4.13.2
Maven Surefire Plugin – 3.0.0-M5
Maven Failsafe Plugin – 3.0.0-M5
Maven Compiler Plugin – 3.8.1
Implementation Steps
Update Properties section in Maven pom.xml
Add repositories and pluginRepository to Maven pom.xml
Add Serenity, Serenity Rest Assured, and JUnit4 dependencies to POM.xml
Update Build Section of pom.xml
Create the Test Code under src/java/test
Create serenity.properties file in the root of the project
Run the tests through the command linewhich generates Serenity Reports.
Project Structure
Step 1 – Update the Properties section in Maven pom.xml
Step 5 – Create the Test Code in src/java/testdirectory
There are 2 ways to create the same test. One approach is to have a Definition file that contains all the test code as shown below.
private static final String URL = "http://dummy.restapiexample.com/api/v1";
public Response response;
@Test
public void verifyValidUser() {
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json").when().get(URL + "/employee/" + id);
SerenityRest.restAssuredThat(response -> response.statusCode(200)
.body("data.id", equalTo(1))
.body("data.employee_salary", equalTo(320800))
.body("data.employee_name", equalTo("Tiger Nixon"))
.body("data.employee_age", equalTo(61)).and()
.body("message", equalTo("Successfully! Record has been fetched.")));
}
@Test
public void verifycreateUser() {
JSONObject data = new JSONObject();
data.put("employee_name", "Shawn Test");
data.put("profile_image", "test.png");
data.put("employee_age", 30);
data.put("employee_salary", 11111);
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json")
.body(data.toString()).when().post(URL + "/create");
SerenityRest.restAssuredThat(response -> response.statusCode(200)
.body("data.employee_salary", equalTo(11111))
.body("data.employee_name", equalTo("Shawn Test"))
.body("data.employee_age", equalTo(30)).and()
.body("message", equalTo("Successfully! Record has been added.")));
}
Another approach is that all tests are split into reusable blocks called “steps”. The main principle of the BDD approach is that we are trying to keep complexity to a high-level human-readable level. First of all, let’s create a separate package to keep our steps. It is always better to keep them separate as it shows which classes contain reusable components. It is better to make steps smaller. So let’s make separate reusable steps from our tests:
import static org.hamcrest.Matchers.equalTo;
import org.json.JSONObject;
import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import net.thucydides.core.annotations.Step;
public class EmployeeSteps {
private static final String URL = "http://dummy.restapiexample.com/api/v1";
public Response response;
@Step("Search user by id {0}")
public void sendUser(int id) {
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json")
.when().get(URL + "/employee/" + id);
}
@Step("Create a new user")
public void createUser() {
JSONObject data = new JSONObject();
data.put("employee_name", "Shawn Test");
data.put("profile_image", "test.png");
data.put("employee_age", 30);
data.put("employee_salary", 11111);
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json")
.body(data.toString()).when().post(URL + "/create");
}
@Step("Verify the status code {0}")
public void verifyStatusCode(int expectedStatusCode) {
SerenityRest.restAssuredThat(response -> response.statusCode(expectedStatusCode));
}
@Step("Verify the user id {0}")
public void verifyId(int expectedId) {
SerenityRest.restAssuredThat(response -> response.body("data.id", equalTo(expectedId)));
}
@Step("Verify the user name {0}")
public void verifyName(String expectedName) {
SerenityRest.restAssuredThat(response -> response.body("data.employee_name", equalTo(expectedName)));
}
@Step("Verify the user salary {0}")
public void verifySalary(int expectedSalary) {
SerenityRest.restAssuredThat(response -> response.body("data.employee_salary", equalTo(expectedSalary)));
}
@Step("Verify the user age {0}")
public void verifyAge(int expectedAge) {
SerenityRest.restAssuredThat(response -> response.body("data.employee_age", equalTo(expectedAge)));
}
@Step("Verify the message {0}")
public void verifyMessage(String expectedMessage) {
SerenityRest.restAssuredThat(response -> response.body("message", equalTo(expectedMessage)));
}
}
Now our steps are ready. Let’s refactor the main class with our tests:
import org.example.SerenityWithRestAssuredDemo.steps.EmployeeSteps;
import org.junit.Test;
import org.junit.runner.RunWith;
import net.serenitybdd.junit.runners.SerenityRunner;
import net.thucydides.core.annotations.Steps;
import net.thucydides.core.annotations.Title;
@RunWith(SerenityRunner.class)
public class EmployeesTest {
@Steps
EmployeeSteps employeeSteps;
@Test
@Title("Get User")
public void verifyValidUser() {
employeeSteps.sendUser(1);
employeeSteps.verifyStatusCode(200);
employeeSteps.verifyId(1);
employeeSteps.verifyName("Tiger Nixon");
employeeSteps.verifyAge(61);
employeeSteps.verifySalary(320800);
employeeSteps.verifyMessage("Successfully! Record has been fetched.");
}
@Test
@Title("Create User")
public void createValidUser() {
employeeSteps.createUser();
employeeSteps.verifyStatusCode(200);
employeeSteps.verifyName("Shawn Test");
employeeSteps.verifyAge(30);
employeeSteps.verifySalary(11111);
employeeSteps.verifyMessage("Successfully! Record has been added.");
}
}
One more important thing we added is the “@RunWith(SerenityRunner.class)” annotation on top of the class. As we have now organized our structure to meet some basic Serenity principles, we are ready to run the test using Serenity. This time (after we added the mentioned annotation) these tests will be run using the “SerenityRunner”. For that we can use exactly the same command to run our tests:
mvn clean verify
In the console, you should find printed messages for tests to start. At the same time under the target directory you can find the HTML-generated report we were talking about before:
You can open the report in any browser:
If you click on any test you should see a detailed description of the test steps:
One of the most important features of the Serenity and REST Assured integration is that by using detailed reporting, you can easily validate all requests and response details even if you are not adding any logs inside tests. Like the example above, for each executed REST request you can click the button “REST Query” and get a detailed request and response description:
There is another very useful Serenity Report – Serenity Symmary.html
As you can see, Serenity and REST Assured provide you with a wonderful combination. REST Assured keeps API testing clean and easy to maintain, while Serenity gives you outstanding test reporting and flexibility in running and grouping your tests inside a test suite.
Complete Source Code: Refer to GitHub for source code.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
As we know, REST Assured is a Java DSL for simplifying testing of REST based services built on top of HTTP Builder. In this tutorial, I’ll create a Test Framework for the testing of REST API using REST Assured and TestNG as test framework. This framework consists of:-
REST Assured – 4.3.3
Java 8 or above
TestNG – 7.4.0
Maven – 3.8.1
Steps to setup Rest API Test Automation Framework with REST Assured and TestNG
Download and Install Java on system
Download and setup Eclipse IDE on system
Setup Maven
Create a new Maven Project
Add REST Assured and TestNG dependencies to the project
Create a TEST file under src/test/java to write the test code.
Run the tests as TestNG Tests
Run the tests from TestNG.xml
TestNG Report Generation
Detailed Step Description
Step 1- Download and Install Java
Java needs to be present on the system to run the tests. Click here to know How to install Java. To know if Java is installed or not on your machine, type this command in the command line. This command will show the version of Java installed on your machine.
java -version
Step 2 – Download and setup Eclipse IDE on system
The Eclipse IDE (integrated development environment) provides strong support for Java developer which is needed to write Java code. Click here to know How to install Eclipse.
Step 3 – Setup Maven
To build a test framework, we need to add a number of dependencies to the project. It is very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool which is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.
To know if Maven is already installed or not on your machine, type this command in the command line. This command will show the version of Maven installed on your machine.
Step 6 – Create a TEST file under src/test/java to write the test code.
To know how to create a JSON Request body using JSONObject, please refer this tutorial.
To know more about priority in TestNG, please refer this tutorial.
public class API_Test {
@Test(description = "To get the details of employee with id 2", priority = 0)
public void verifyUser() {
// Given
given()
// When
.when()
.get("http://dummy.restapiexample.com/api/v1/employee/2")
// Then
.then()
.statusCode(200)
.statusLine("HTTP/1.1 200 OK")
// To verify booking id at index 3
.body("data.employee_name", equalTo("Garrett Winters"))
.body("message", equalTo("Successfully! Record has been fetched."));
}
@Test(description = "To create a new employee", priority = 1)
public void createUser() {
JSONObject data = new JSONObject();
data.put("employee_name", "APITest");
data.put("employee_salary", "99999");
data.put("employee_age", "30");
// GIVEN
given()
.baseUri("http://dummy.restapiexample.com/api")
.contentType(ContentType.JSON)
.body(data.toString())
// WHEN
.when()
.post("/v1/create")
// THEN
.then()
.statusCode(200)
.body("data.employee_name", equalTo("APITest"))
.body("message", equalTo("Successfully! Record has been added."));
}
}
Step 7 – Test Execution through TestNG
Go to Runner class and right click Run As TestNG Test. The tests will run as TestNG tests.
This is how the execution console will look like.
Step 8 – Run the tests from TestNG.xml
Create a TestNG.xml as shown below and run the tests as TestNG. Here, the tests are present in class – com.example.Selenium_TestNGDemo.API_Test.
<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "Suite1">
<test name = "Test Demo">
<classes>
<class name = "com.example.Selenium_TestNGDemo.API_Test"/>
</classes>
</test>
</suite>
Step 9 – TestNG Report Generation
After test execution, refresh the project, a new folder with name test-output will be generated. This folder contains the reports generated by TestNG. The structure of folder test-output looks like as shown below.
We are interested in ’emailable-report.html’ report. Open ’emailable-report.html’, as this is a html report open it with browser. Below image shows emailable-report.html.
TestNG also produce “index.html” report and it resides under test-output folder. Below image shows index.html report. This report contains the high level summary of the tests.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Selects the specified property in a parent object.
[‘property’]
Selects the specified property in a parent object. Be sure to put single quotes around the property name.Tip: Use this notation if the property name contains special characters such as spaces, or begins with a character other than A..Za..z_.
[n]
Selects the n-th element from an array. Indexes are 0-based.
[index1,index2,…]
Selects array elements with the specified indexes. Returns a list.
..property
Recursive descent: Searches for the specified property name recursively and returns an array of all values with this property name. Always returns a list, even if just one property is found.
*
Wildcard selects all elements in an object or an array, regardless of their names or indexes.
[start:end] [start:]
Selects array elements from the start index and up to, but not including, end index. If end is omitted, selects all elements from start until the end of the array. Returns a list.
[:n]
Selects the first n elements of the array. Returns a list.
[-n:]
Selects the last n elements of the array. Returns a list.
[?(expression)]
Selects all elements in an object or array that match the specified filter. Returns a list.
[(expression)]
Script expressions can be used instead of explicit property names or indexes. An example is [(@.length-1)] which selects the last item in an array. Here, length refers to the length of the current array rather than a JSON field named length.
@
Used in filter expressions to refer to the current node being processed.
Below is the sample JSON which I am using for extraction examples.
String jsonString = {
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
To extract all books present in store:-
String allBooks = JsonPath.read(jsonString, "$..*").toString();
System.out.println("--------------- All books in the store --------------");
System.out.println(allBooks);
Below are examples which shows how to extract different nodes from a JSON Body. I have used above JSON Body for these examples.
// All bicycles in the store
String allBicycles = JsonPath.read(jsonString, "$..bicycle").toString();
System.out.println("--------------- All bicycles in the store ---------------");
System.out.println(allBicycles);
// The number of books
String noOfBooks = JsonPath.read(jsonString, "$..book.length()").toString();
System.out.println("--------------- The number of books ---------------");
System.out.println(noOfBooks);
// The authors of all books
String authors = JsonPath.read(jsonString, "$.store.book[*].author").toString();
System.out.println("--------------- Author of all Books ---------------");
System.out.println(authors);
// All authors
String allAuthors = JsonPath.read(jsonString, "$..author").toString();
System.out.println("--------------- All Authors ---------------");
System.out.println(allAuthors);
// All details of the store
String store = JsonPath.read(jsonString, "$.store.*").toString();
System.out.println("--------------- All details of the store ---------------");
System.out.println(store);
// Price of store
String storePrice = JsonPath.read(jsonString, "$.store..price").toString();
System.out.println("--------------- price of store ---------------");
System.out.println(storePrice);
Below are the examples where I have extracted specific book (nodes) from the JSON body.
// Third book
String thirdBook = JsonPath.read(jsonString, "$..book[2]").toString();
System.out.println("--------------- third book ---------------");
System.out.println(thirdBook);
// first Last Book
String firstLastBook = JsonPath.read(jsonString, "$..book[-1]").toString();
System.out.println("--------------- first Last Book ---------------");
System.out.println(firstLastBook);
// first two Books
String firstTwoBooks = JsonPath.read(jsonString, "$..book[0,1]").toString();
System.out.println("--------------- first Two Books ---------------");
System.out.println(firstTwoBooks);
// books from index 0 (inclusive) until index 2 (exclusive)
String booksRange = JsonPath.read(jsonString, "$..book[:2]").toString();
System.out.println("--------------- books from index 0 (inclusive) until index 2 (exclusive) ---------------");
System.out.println(booksRange);
// All books from index 1 (inclusive) until index 2 (exclusive)
String booksRange1 = JsonPath.read(jsonString, "$..book[1:2]").toString();
System.out.println("------------ All books from index 1 (inclusive) until index 2 (exclusive) -----------");
System.out.println(booksRange1);
// Book number one from tail
String bottomBook = JsonPath.read(jsonString, "$..book[1:]").toString();
System.out.println("--------------- Book number one from tail ---------------");
System.out.println(bottomBook);
Filters are logical expressions used to filter arrays. Below are the examples of a JSONPath expression with the filters.
// All books in store expensive than 10
String expensiveBook = JsonPath.read(jsonString, "$.store.book[?(@.price > 10)]").toString();
System.out.println("--------------- All books in store costlier than 10 ---------------");
System.out.println(expensiveBook);
// All books in store that are not "expensive"
String notExpensiveBook = JsonPath.read(jsonString, "$..book[?(@.price <= $['expensive'])]").toString();
System.out.println("--------------- All books in store that are not expensive ---------------");
System.out.println(notExpensiveBook);
// All books in store that are equal to price 8.95
String comparePrice = JsonPath.read(jsonString, "$.store.book[?(@.price == 8.95)]").toString();
System.out.println("--------------- All books in store that are not expensive ---------------");
System.out.println(comparePrice);
// All books matching regex (ignore case)
String regxExample = JsonPath.read(jsonString, "$..book[?(@.author =~ /.*REES/i)]").toString();
System.out.println("--------------- All books matching regex (ignore case) ---------------");
System.out.println(regxExample);
// All books with price equal to mentioned list of prices
String priceList = JsonPath.read(jsonString, "$..book[?(@.price in ['12.99', '8.99'])]").toString();
System.out.println("--------------- All books with price equal to mentioned list of prices ---------------");
System.out.println(priceList);
// All books with price NOT equal to mentioned list of prices
String excludePriceList = JsonPath.read(jsonString, "$..book[?(@.price nin ['12.99', '8.99'])]").toString();
System.out.println("---------- All books with price NOT equal to mentioned list of prices ---------");
System.out.println(excludePriceList);
// All books with specified substring (case-sensitive)
String substringExample = JsonPath.read(jsonString, "$..book[?(@.author contains 'Melville')]").toString();
System.out.println("--------------- All books with specified substring (case-sensitive) ---------------");
System.out.println(substringExample);
// All books with an ISBN number
String specificBook = JsonPath.read(jsonString, "$..book[?(@.isbn)]").toString();
System.out.println("--------------- All books with an ISBN number ---------------");
System.out.println(specificBook);
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Assertion is a way to verify that the expected result and the actual result matches or not in the test case. A test is considered successful ONLY if it is completed without throwing any exception. If the current value and the expected value match then the assertion passes and when the assertion passes nothing happens. But when an assertion fails it will fail the test case.
There are various ways to perform assertions in API Testing. For API Testing, we are using Rest Assured which uses either Hamcrest or JUnit assertions. We are going to discuss Hamcrest Assertions here.
What is Hamcrest?
Hamcrest is a framework for writing matcher objects allowing ‘match’ rules to be defined declaratively. We do not need to add Hamcrest depdendency explicitly as Rest-Assured 4.3.3 version include by itself. To know more about Hamcrest, please refer this link.
Below is an example of JSON Response. I will perform various assertions on this JSON Response.
To use hamcrest assertion please import the Matchers class static member.
Number related assertions
equalTo – It checks whether the retrieved number from response is equal to the expected number.
greaterThan – checks extracted number is greater than the expected number.
greaterThanOrEqualTo – checks whether the extracted number is greater than equal to the expected number.
lessThan – It checks whether the retrieved number from response is lesser than to the expected number.
lessThanOrEqualTo – It checks whether the retrieved number from response is lesser than or equal to the expected number.
Below assertions are imported from package shown below:-
Below are the examples to show the use of number related assertions.
public class HamcrestExample {
public String endpoint = "https://restful-booker.herokuapp.com/booking/1";
@Test
public void numberAssertions() {
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint).then()
.body("totalprice", equalTo(813));
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice",greaterThan(500));
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice",greaterThanOrEqualTo(500));
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice",lessThan(1000));
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice",lessThanOrEqualTo(1000));
}
}
String related Assertions
equalTo – It checks whether the extracted string from JSON is equal to the expected string.
equalToIgnoringCase – It checks whether the extracted string from JSON is equal to the expected string without considering the case (small or capital).
equalToIgnoringWhiteSpace – It checks whether the extracted string from JSON is equal to the expected string by considering the white spaces.
containsString– It checks whether the extracted string from JSON contains the expected string as a substring.
startsWith– It checks whether the extracted string from JSON is starting with a given string or character.
endsWith – It checks whether the extracted string from JSON is ending with a given string or character.
Below assertions are imported from package shown below:-
Below are the examples to show the use of collection related assertions.
public class HamcrestExample {
public String endpoint = "https://restful-booker.herokuapp.com/booking/1";
@Test
public void collectionAssertions() {
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice1",is(nullValue()));
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("bookingdates",hasKey("checkin"));
}
}
Not Assertion
The not assertion inverts the meaning of the other assertions. For example, if you want to perform negative assertions, then we can use any assertions with NOT.
Below assertion is imported from package shown below:-
Below are the examples to show the use of negative assertions.
public class HamcrestExample {
public String endpoint = "https://restful-booker.herokuapp.com/booking/1";
@Test
public void negativeAssertions() {
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint)
.then().body("totalprice",not(equalTo(874)));
}
}
Multiple Assert Statements
In the below exaple, all 3 asserstions will fail, but it will only execute assertion and first assertion is failed, then other assertions will not be executed.
public class HamcrestExample {
public String endpoint = "https://restful-booker.herokuapp.com/booking/1";
@Test
public void test() {
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint).then()
.body("firstname", equalTo("Jim")) // will fail
.body("lastname", equalTo("Smith")) // will fail
.body("totalprice", equalTo(314)); // will fail
}
}
To execute all the assertions present in the test case we have to combine all the assertion into a single body, just like below. You can see that all the assertions are failed and they are shown in the response.
public class HamcrestExample {
public String endpoint = "https://restful-booker.herokuapp.com/booking/1";
@Test
public void test() {
RestAssured.given().contentType(ContentType.JSON)
.when().get(endpoint).then()
.body("firstname", equalTo("Jim"), // will fail
"lastname", equalTo("Smith"), // will fail
"totalprice", equalTo(314)); // will fail
}
}
I have tried to show the use of few of the most commonly used assertion methods. There are many more methods avilable in Hamcrest package. To know about other methods, write import static org.hamcrest.Matchers and add (.) at the end, it will show the list of all the methods available in Hamcrest.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
JSONArray represents an immutable JSON array (an ordered sequence of zero or more values). It also provides an unmodifiable list view of the values in the array.
JSON array can store multiple value types. The values in a JSONArray can be of the following types: JsonObject, JsonArray, JsonString, JsonNumber, JsonValue.TRUE, JsonValue.FALSE, and JsonValue.NULL.
2. The array index begins with 0.
3. The square brackets [ ] are used to declare the JSON array.
An API may accept a JSON Array payload as a request body. Imagine, we want to add employee details of more than one employee in the below example. In this case, we can pass multiple JSON objects within a JSON array. I have explained 2 ways to create JSON Object – map or JsonObject. Refer to any one of the tutorials to get to know about the creation of JSON Object.
To create a JSON Array, we need to add a maven dependency, as shown below.
We can create a JSON Object using a Map in Java. A JSON Object is a key-value pair and can be easily created using a Java Map. A Map in Java also represents a collection of key-value pairs.
I have created a simple Java map and filled it with the values that represent JSON properties.
@Test
public void passBodyAsMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("employee_name", "MapTest");
map.put("employee_salary", "99999");
map.put("employee_age", "30");
map.put("profile_image", "test.png");
RestAssured.given()
.contentType(ContentType.JSON)
.body(map)
.log().all()
.when()
.post("http://dummy.restapiexample.com/api/v1/create")
.then()
.assertThat().statusCode(200)
.body("data.employee_name", equalTo("MapTest"))
.body("data.employee_age", equalTo("30"))
.body("data.employee_salary", equalTo("99999"))
.body("message", equalTo("Successfully! Record has been added.")).log().all();
}
The Request body as well as response body will look as shown below:-
Above one is a simple JSON Request Body. Lets take an example of Complex Request Body or nested Request Body as shown below.
@Test
public void passBodyAsMultipleMap() {
// First JSON Object using Hash Map
Map<String, Object> data = new HashMap<String, Object>();
data.put("employee_name", "MapTest");
data.put("profile_image", "test.png");
// Second JSON Object using Hash Map
Map<String, String> msg = new HashMap<String, String>();
msg.put("updated_message", "Details of New Resource");
msg.put("employee_age", "30");
data.put("details", msg);
data.put("employee_salary", "99999");
RestAssured.given().contentType(ContentType.JSON).body(data).log().all()
// WHEN
.when().post("http://dummy.restapiexample.com/api/v1/create")
// THEN
.then().assertThat().statusCode(200).body("data.employee_name", equalTo("MapTest"))
.body("data.details.updated_message", equalTo("Details of New Resource"))
.body("data.details.employee_age", equalTo("30")).body("data.employee_salary", equalTo("99999"))
.body("message", equalTo("Successfully! Record has been added.")).log().all();
}
}
The Request body as well as response body will look as shown below image. First part is the body of request and second part is the response provided by API.
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
In the last tutorial, I have explained How to test POST Request using Rest Assured where request body is in String Format. In this tutorial, I will create a Request body using JSON Object in Rest Assured. This request body can be used for POST or PUT operations.
In the previous post, you must have observed that I had hard-coded the JSON request body in a string format. It is not a good practice if you have the dynamic payload or want to create a payload at run time or parameterized one. It is always recommended to create a payload in such a way that you can easily maintain, manage, update, and retrieve values from it. This can be achieved by JSONObject or JSONArray.
A JSONObjectis an unordered collection of key and value pairs, resembling Java’s native Map implementations. JSON stores data as a key-value pair. Key is left side and value is the right side and a semicolon is used to separate both. One key-value pair is separated from another key-value pair using comma (,).
The internal form is an object having to get and opt methods for accessing the values by name and put methods for adding or replacing values by name. The values can be any of these types: Boolean, JSONArray, JSONObject, Number, String, or the JSONObject.NULL object.
To create a request body using JSON Object, we need to add a maen dependency.
JSONObjectexposes an API similar to Java’s Map interface. Below is an example of creating a request from JSON Object. Here, Id is auto-generated attribute. We are using the put() method and supply the key and value as an argument. I am using a logger just to print the JSON body in the Console.
@Test
public void passBodyAsJsonObject() {
JSONObject data = new JSONObject();
data.put("employee_name", "MapTest");
data.put("profile_image", "test.png");
data.put("employee_age", "30");
data.put("employee_salary", "11111");
RestAssured.given()
.contentType(ContentType.JSON)
.body(data.toString())
.log().all()
.when()
.post("http://dummy.restapiexample.com/api/v1/create")
.then()
.assertThat().statusCode(200)
.body("data.employee_name", equalTo("MapTest"))
.body("data.employee_age", equalTo("30"))
.body("data.employee_salary", equalTo("11111"))
.body("data.profile_image", equalTo("test.png"))
.body("message", equalTo("Successfully! Record has been added."))
.log().all();
}
The Request body will look as shown below:-
The texts produced by the toString() methods strictly conform to the JSON syntax rules.
.body(data.toString())
Above one is a simple JSON Request Body. Lets take an example of Complex Request Body or nested Request Body.
We need to create two JSONObject here. One will hold overall key-value pairs and another JSONObject will hold only employee_details key-value pairs.
Below is the example which shows how to create a complex JSON request body using JSONObject.
@Test
public void passBodyAsJsonObjectDemo() {
//First JSONObject
JSONObject data = new JSONObject();
data.put("profile_image", "test.png");
//Second JSONObject
JSONObject detail = new JSONObject();
detail.put("updated_message", "Details of New Resource");
detail.put("employee_age", "30");
data.put("employee_details", detail);
data.put("employee_name", "MapTest");
data.put("employee_salary", "11111");
RestAssured.given()
.contentType(ContentType.JSON)
.body(data.toString())
.log().all()
.when()
.post("http://dummy.restapiexample.com/api/v1/create")
.then()
.assertThat().statusCode(200)
.body("data.employee_name", equalTo("MapTest"))
.body("data.employee_details.employee_age", equalTo("30"))
.body("data.employee_details.updated_message", equalTo("Details of New Resource"))
.body("data.employee_salary", equalTo("11111")).body("data.profile_image", equalTo("test.png"))
.body("message", equalTo("Successfully! Record has been added."))
.log().all();
}
}
The Request body will look as shown below:-
We are done. Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!