REST Assured: CRUD Framework for API Testing
Design Pattern for API Testing using Java Rest Assured Library.
Join the DZone community and get the full member experience.
Join For FreeREST Assured Java Library - API Testing
REST Assured is an open-source (free) Java library available for testing primarily the RESTful web services. REST Assured is a Java domain-specific language (DSL) for simplifying testing of REST-based web services built on top of HTTP. It supports most commonly used HTTP verbs like GET, POST, PUT/PATCH DELETE, OPTIONS, HEAD which can be used to validate & verify the response of these requests.
Web API Communication
Designing Test Cases
Implementation of Test Cases: CRUD Pattern
Step 1: Create a Maven Java project in Eclipse with all the required dependencies in pom.xml as shown below:
Dependency Details io.rest-assured --> Rest Assured for testing API interactions(request & response),extract json/xml path. org.testng --> Designing the Test Frmework using TestNG Classes. com.google.code.gson --> Represent the request body data in the from of java objects like Map <--> JSONformat. com.github.javafaker --> To supply fake data for testing while sending request. com.jayway.jsonpath --> Extract data specifically from JSON file using jayway jsonpath.
xxxxxxxxxx
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rest</groupId>
<artifactId>RestAPITestingProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<rest.version>4.3.3</rest.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.rest-assured/json-path -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>${rest.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
<version>${rest.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.javafaker/javafaker -->
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
</project>
Step 2: Design the Routes.java class to register all the available services with end-points as shown below:
xxxxxxxxxx
package api.engine.endpoints;
/**
*
* @author aswani.kumar.avilala
* Swagger URI --> https://petstore.swagger.io
* Routes class allow the testers to design the end-points for all services that are available
*/
public class Routes {
/**
* The base uri is the resource where all the <b>services</b> are running.
*/
public static String base_uri ="https://petstore.swagger.io/v2";
/**
* The post uri route the request to a service to create an user.
*/
public static String post_uri ="/user";
/**
* The get,put,delete uri routes the request to respective services
to read,update,delete an user using username.
*/
public static String get_put_delete_uri="/user/{username}";
}
Step 3: Design the UserEndpoints.java class to perform Create, Read, Update, Delete requests to the services using the above-created end-points as shown below:
x
package api.engine.endpoints;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
/**
*
* @author aswani.kumar.avilala
* User Endpoints.java class is designed to to perform Create, Read, Update, Delete requests to the User services
*/
public class UserEndpoints {
public static Response createUser(String payload)
{
RestAssured.baseURI=Routes.base_uri;
Response response=RestAssured.
given().contentType(ContentType.JSON).accept(ContentType.JSON).body(payload).
when().post(Routes.post_uri);
return response;
}
public static Response readUser(String userName)
{
RestAssured.baseURI=Routes.base_uri;
Response response=RestAssured.
given().pathParam("username",userName).
when().get(Routes.get_put_delete_uri);
return response;
}
public static Response updateUser(String userName,String payload)
{
RestAssured.baseURI=Routes.base_uri;
Response response=RestAssured.
given().contentType(ContentType.JSON).accept(ContentType.JSON).
pathParam("username",userName).body(payload).
when().put(Routes.get_put_delete_uri);
return response;
}
public static Response deleteUser(String userName)
{
RestAssured.baseURI=Routes.base_uri;
Response response=RestAssured.
given().pathParam("username",userName).
when().delete(Routes.get_put_delete_uri);
return response;
}
}
Step 4: Design the User.java class to represents the data structure of the user payload which is in JSON format as shown below:
xxxxxxxxxx
package api.payload;
/**
*
* @author aswani.kumar.avilala
* User class represents the data structure of the user pay load which is in JSON format
*
*/
public class User {
private Integer userId;
private String userName;
private String firstName;
private String lastName;
private String email;
private String password;
private String phone;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String toString() {
return "User [userId=" + userId + ", userName=" + userName + ", firstName=" + firstName + ", lastName="
+ lastName + ", email=" + email + ", password=" + password + ", phone="
+ phone + "]";
}
}
Step 5: Design the TestEndpoints.java class to perform the API Testing for all the services using the TestNG class as shown below:
x
package com.test;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.github.javafaker.Faker;
import com.google.gson.Gson;
import api.engine.endpoints.UserEndpoints;
import api.payload.User;
import io.restassured.response.Response;
/**
*
* @author aswani.kumar.avilala
* Perform API Testing for the services using CRUD Design Pattern
*/
public class TestEndpoints {
Faker faker;
User userPayload;
public void beforeTest()
{
System.out.println("*****************USERNAME UNDER TEST**********************************");
faker=new Faker();
userPayload=new User();
userPayload.setUserId(faker.idNumber().hashCode());
userPayload.setUserName(faker.name().username());
userPayload.setFirstName(faker.name().firstName());
userPayload.setLastName(faker.name().lastName());
userPayload.setEmail(faker.internet().safeEmailAddress());
userPayload.setPassword(faker.internet().password(5,10));
userPayload.setPhone(faker.phoneNumber().cellPhone());
System.out.println("Some Random username genereated by Faker:\t"+userPayload.getUserName());
System.out.println("**********************************************************************");
}
(priority = 1)
public void testPostUser()
{
Map<String,Object> bodyParams=new HashMap<String,Object>();
bodyParams.put("id",userPayload.getUserId());
bodyParams.put("username",userPayload.getUserName());
bodyParams.put("firstName",userPayload.getFirstName());
bodyParams.put("lastName",userPayload.getLastName());
bodyParams.put("email",userPayload.getEmail());
bodyParams.put("password",userPayload.getPassword());
bodyParams.put("phone",userPayload.getPhone());
bodyParams.put("userStatus",0);
String payload=new Gson().toJson(bodyParams);
System.out.println("*************************{POST}***************************************");
Response response=UserEndpoints.createUser(payload);
response.then().log().all();
Assert.assertEquals(response.getStatusCode(),200);
Assert.assertTrue(response.getStatusLine().contains("OK"));
System.out.println("**********" +this.userPayload.getUserName()+" is created ************");
}
(priority = 2)
public void testGetUserByName()
{
System.out.println("*************************{GET}****************************************");
Response response=UserEndpoints.readUser(this.userPayload.getUserName());
response.then().log().body().statusCode(200);
System.out.println("************ "+this.userPayload.getUserName()+" is fetched **********");
}
(priority = 3)
public void testUpdateUserByName()
{
Map<String,Object> bodyParams=new HashMap<String,Object>();
bodyParams.put("id",userPayload.getUserId());
bodyParams.put("username",userPayload.getUserName());
/**
* update starts from here based on existing user name
*/
bodyParams.put("firstName",userPayload.getFirstName()+" is my first name");
bodyParams.put("lastName",userPayload.getLastName()+" is my last name");
bodyParams.put("email",userPayload.getEmail()+" is my email");
bodyParams.put("password",userPayload.getPassword()+" is my password");
bodyParams.put("phone",userPayload.getPhone()+" is my phone number");
bodyParams.put("userStatus",1);
String payload=new Gson().toJson(bodyParams);
System.out.println("*************************{UPDATE}************************************");
Response response=UserEndpoints.updateUser(this.userPayload.getUserName(), payload);
response.then().log().body().statusCode(200);
Response afterUpdateResponse=UserEndpoints.readUser(this.userPayload.getUserName());
afterUpdateResponse.then().log().body().statusCode(200);
System.out.println("********* "+this.userPayload.getUserName()+" is updated ************");
}
(priority = 4)
public void testDeleteUserByName()
{
System.out.println("*************************{DELETE}************************************");
Response response=UserEndpoints.deleteUser(this.userPayload.getUserName());
response.then().log().body().statusCode(200);
System.out.println("******** "+this.userPayload.getUserName()+" is deleted *************");
}
}
Maven Java Project Structure:
***Note: Run the TestEndpoints.java class as TestNG test to observe the below output.
Output:
xxxxxxxxxx
[RemoteTestNG] detected TestNG version 7.3.0
*****************USERNAME UNDER TEST**********************************
Some Random username genereated by Faker: elvin.batz
**********************************************************************
*************************{POST}***************************************
HTTP/1.1 200 OK
Date: Tue, 27 Apr 2021 16:56:10 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Server: Jetty(9.2.9.v20150224)
{
"code": 200,
"type": "unknown",
"message": "1667689440"
}
******** elvin.batz is created **************************************
*************************{GET}****************************************
{
"id": 1667689440,
"username": "elvin.batz",
"firstName": "Marlys",
"lastName": "Kub",
"email": "gilberto.adams@example.com",
"password": "qy3mlpj",
"phone": "1-515-965-2999",
"userStatus": 0
}
************ elvin.batz is fetched *********************************
*************************{UPDATE}************************************
{
"code": 200,
"type": "unknown",
"message": "1667689440"
}
{
"id": 1667689440,
"username": "elvin.batz",
"firstName": "Marlys is my first name",
"lastName": "Kub is my last name",
"email": "gilberto.adams@example.com is my email",
"password": "qy3mlpj is my password",
"phone": "1-515-965-2999 is my phone number",
"userStatus": 1
}
********* elvin.batz is updated ************************************
*************************{DELETE}************************************
{
"code": 200,
"type": "unknown",
"message": "elvin.batz"
}
******** elvin.batz is deleted *************************************
PASSED: testPostUser
PASSED: testGetUserByName
PASSED: testUpdateUserByName
PASSED: testDeleteUserByName
=====================================================================
Default test
Tests run: 4, Failures: 0, Skips: 0
=====================================================================
=====================================================================
Default suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
=====================================================================
*** Note: Each time you run the code, a different username is generated by the Java Faker class.
Conclusion:
Hence the above demo represents the completion of design using CRUD pattern, wherein we can modularize and separate the data layer, API calls, test codes. These test cases are completely designed independently of the testing framework. This framework ensures to have code reusability, modularity, and better maintenance of the codes.
Opinions expressed by DZone contributors are their own.
Comments