These days there are many tools available to test REST based APIs - some of them are quite mature and feature-rich like Citrus, soapUI and Postman; but these are built only for API testing and trying to use them for other general purposes is often difficult.
If you already have a mature framework and want to 'incrementally' test APIs also as part of your existing codebase for functional automation, and want to save time in building a new framework around new tools, then you can use RestAssured in your existing framework.
RestAssured is a very capable java library for testing APIs and it even supports BDD-style spec.
Maven dependencies for Rest Assured -
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>3.3.0</version>
</dependency>
Sample code for working with RestAssured -
package main.java.com.automation.keyword.app;
import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static io.restassured.module.jsv.JsonSchemaValidator.*;
import static org.hamcrest.Matchers.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.apache.log4j.Logger;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
public class RESTPoC {
private static Logger log = Logger.getLogger(RESTPoC.class.getName());
/*
* Variables for specification of different APIs though we may have only a single response specification
*/
private RequestSpecification raceReqSpec;
private RequestSpecification postmanReqSpec;
private ResponseSpecification respSpec;
private String url = "";
/*
* Function to set the config for all Req/Resp specifications
* But somehow its use is not getting implemented correctly as of now
*/
public void restConfig() {
log.info("setting proxy...");
// RestAssured.proxy("localhost", 8888);
log.info("configuring common requestSpecification...");
RequestSpecification requestSpecification = new RequestSpecBuilder().
// addHeader("Content-type", "json").
// addHeader("Accept", "application/json").
build();
log.info("setting this as the specification for all REST requests...");
RestAssured.requestSpecification = requestSpecification;
}
public String getURL(String apiName) {
switch (apiName.toLowerCase()) {
case "google-books":
url = "https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699";
break;
case "google-books-java":
url = "https://www.googleapis.com/books/v1/volumes?title:java";
break;
case "f1-api":
url = "http://ergast.com/api/f1/2018/circuits.json";
break;
case "postman-get":
url = "https://postman-echo.com/GET";
break;
case "400":
url = "http://ergast.com/api/f1/2018/circuits1.json";
break;
case "404":
url = "http://ergast.com/api/f1/2018/circuits.json 1";
break;
default:
break;
}
log.info("Request URL: " + url);
return url;
}
public String setURL() {
url = "https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699";
// url = "http://ergast.com/api/f1/2018/circuits.json";
// url = "https://postman-echo.com/GET";
log.info("Request URL: " + url);
return url;
}
/*
* This function does not take a Req Specification to get the Response from the resourceURL
* It has BDD style coding
* It also logs all requests and response steps
*/
public void getResponseBDD() {
given().log().all().
when().get(url).
then().log().all().statusCode(200);
}
/*
* This function does not take a Req Specification to get the Response from the resourceURL
* Nor does this uses BDD style coding
* @param resourceURL
*/
public Response getResponseDirectlyNoReqSpec(String resourceURL) {
Response rsp = null;
RequestSpecification rq = RestAssured.given();
rsp = rq.get(resourceURL);
log.info("------------------------------------------------------------------");
log.info("URL: " + resourceURL + " has Response: " + "\n" + rsp.asString());
log.info("------------------------------------------------------------------");
return rsp;
}
public Boolean chkInvalidResponse() {
Response rsp;
Boolean result;
// rsp = getResponseDirectlyNoReqSpec(getURL("f1-api") + " 12312");
rsp = getResponseDirectlyNoReqSpec(getURL("404"));
if (getStatusCode(rsp) == 200) {
log.info("Valid response received");
result = true;
} else {
getStatusLine(rsp);
getAllHeaders(rsp);
result = false;
}
return result;
}
public void sampleJsonPathExp() {
Response rsp;
rsp = getResponseDirectlyNoReqSpec(getURL("google-books-java"));
JsonPath jp = rsp.jsonPath();
}
public void chkResponseGoogleBooksAPI() {
Response rsp = getResponseDirectlyNoReqSpec(getURL("google-books"));
if (getStatusCode(rsp) == 200) {
getAllHeaders(rsp);
} else {
getAllHeaders(rsp);
}
}
/*
* Function to check response of F1 API via JsonPath
*/
public void chkResponseF1API() {
Response rsp = getResponseDirectlyNoReqSpec(getURL("f1-api"));
String contentType = "";
// Proceed only if response is 200
if (getStatusCode(rsp) == 200) {
getStatusLine(rsp);
getAllHeaders(rsp);
contentType = getHeaderValue(rsp, "Content-type");
getHeaderValue(rsp, "Server");
// Proceed only if response type is JSON
if (contentType.toLowerCase().contains("json")) {
JsonPath jp = rsp.jsonPath();
log.info("Series Name: " + jp.get("MRData.series").toString().toUpperCase());
log.info("Year: " + jp.get("MRData.CircuitTable.season"));
log.info("Circuit Name: " + jp.get("MRData.CircuitTable.Circuits[0].circuitName"));
log.info("Circuit Country: " + jp.get("MRData.CircuitTable.Circuits[0].Location.country"));
log.info("Total Circuits: " + jp.get("MRData.total"));
log.info("Getting name and country of each circuit -------------------------------------");
for (int i = 0; i < Integer.parseInt(jp.get("MRData.total")); i++) {
log.info("Circuit Name: " + jp.get("MRData.CircuitTable.Circuits[" + i + "].circuitName"));
log.info("Circuit Country: " + jp.get("MRData.CircuitTable.Circuits[" + i + "].Location.country"));
}
}
}
// TestNG Assert library
assertTrue(contentType.toLowerCase().contains("json"));
// assertEquals(contentType, "application/json");
}
// Status Code is of type int
public int getStatusCode(Response response) {
int statusCode;
statusCode = response.getStatusCode();
log.info("Status Code: " + statusCode);
return statusCode;
}
// Status msg is of type string
public String getStatusLine(Response response) {
String statusLine;
statusLine = response.getStatusLine() + "";
log.info("Status Msg: " + statusLine);
return statusLine;
}
public String getHeaderValue(Response response, String headerName) {
String headerValue = "";
headerValue = response.getHeader(headerName) + "";
log.info("Header name: " + headerName + " - value: " + headerValue);
return headerValue;
}
public void getAllHeaders(Response response) {
log.info("Getting value of all Headers via Headers object ---------------------------------");
Headers allHeaders = response.getHeaders();
for (Header header : allHeaders) {
log.info("Header name: " + header.getName() + " - value: " + header.getValue());
}
}
/*
* Keyword sort of methods Invoking requests without first calling the config Req/Resp is successful when common
* spec for response is not used
*/
public void invokeRestNoConfig() {
getURL("f1-api");
getResponseBDD();
}
public static void main(String[] args) {
RESTPoC rd = new RESTPoC();
rd.chkResponseF1API();
rd.chkResponseGoogleBooksAPI();
rd.chkInvalidResponse();
rd.sampleJsonPathExp();
}
}
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>3.3.0</version>
</dependency>
Sample code for working with RestAssured -
package main.java.com.automation.keyword.app;
import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static io.restassured.module.jsv.JsonSchemaValidator.*;
import static org.hamcrest.Matchers.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.apache.log4j.Logger;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
public class RESTPoC {
private static Logger log = Logger.getLogger(RESTPoC.class.getName());
/*
* Variables for specification of different APIs though we may have only a single response specification
*/
private RequestSpecification raceReqSpec;
private RequestSpecification postmanReqSpec;
private ResponseSpecification respSpec;
private String url = "";
/*
* Function to set the config for all Req/Resp specifications
* But somehow its use is not getting implemented correctly as of now
*/
public void restConfig() {
log.info("setting proxy...");
// RestAssured.proxy("localhost", 8888);
log.info("configuring common requestSpecification...");
RequestSpecification requestSpecification = new RequestSpecBuilder().
// addHeader("Content-type", "json").
// addHeader("Accept", "application/json").
build();
log.info("setting this as the specification for all REST requests...");
RestAssured.requestSpecification = requestSpecification;
}
public String getURL(String apiName) {
switch (apiName.toLowerCase()) {
case "google-books":
url = "https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699";
break;
case "google-books-java":
url = "https://www.googleapis.com/books/v1/volumes?title:java";
break;
case "f1-api":
url = "http://ergast.com/api/f1/2018/circuits.json";
break;
case "postman-get":
url = "https://postman-echo.com/GET";
break;
case "400":
url = "http://ergast.com/api/f1/2018/circuits1.json";
break;
case "404":
url = "http://ergast.com/api/f1/2018/circuits.json 1";
break;
default:
break;
}
log.info("Request URL: " + url);
return url;
}
public String setURL() {
url = "https://www.googleapis.com/books/v1/volumes?q=isbn:0747532699";
// url = "http://ergast.com/api/f1/2018/circuits.json";
// url = "https://postman-echo.com/GET";
log.info("Request URL: " + url);
return url;
}
/*
* This function does not take a Req Specification to get the Response from the resourceURL
* It has BDD style coding
* It also logs all requests and response steps
*/
public void getResponseBDD() {
given().log().all().
when().get(url).
then().log().all().statusCode(200);
}
/*
* This function does not take a Req Specification to get the Response from the resourceURL
* Nor does this uses BDD style coding
* @param resourceURL
*/
public Response getResponseDirectlyNoReqSpec(String resourceURL) {
Response rsp = null;
RequestSpecification rq = RestAssured.given();
rsp = rq.get(resourceURL);
log.info("------------------------------------------------------------------");
log.info("URL: " + resourceURL + " has Response: " + "\n" + rsp.asString());
log.info("------------------------------------------------------------------");
return rsp;
}
public Boolean chkInvalidResponse() {
Response rsp;
Boolean result;
// rsp = getResponseDirectlyNoReqSpec(getURL("f1-api") + " 12312");
rsp = getResponseDirectlyNoReqSpec(getURL("404"));
if (getStatusCode(rsp) == 200) {
log.info("Valid response received");
result = true;
} else {
getStatusLine(rsp);
getAllHeaders(rsp);
result = false;
}
return result;
}
public void sampleJsonPathExp() {
Response rsp;
rsp = getResponseDirectlyNoReqSpec(getURL("google-books-java"));
JsonPath jp = rsp.jsonPath();
}
public void chkResponseGoogleBooksAPI() {
Response rsp = getResponseDirectlyNoReqSpec(getURL("google-books"));
if (getStatusCode(rsp) == 200) {
getAllHeaders(rsp);
} else {
getAllHeaders(rsp);
}
}
/*
* Function to check response of F1 API via JsonPath
*/
public void chkResponseF1API() {
Response rsp = getResponseDirectlyNoReqSpec(getURL("f1-api"));
String contentType = "";
// Proceed only if response is 200
if (getStatusCode(rsp) == 200) {
getStatusLine(rsp);
getAllHeaders(rsp);
contentType = getHeaderValue(rsp, "Content-type");
getHeaderValue(rsp, "Server");
// Proceed only if response type is JSON
if (contentType.toLowerCase().contains("json")) {
JsonPath jp = rsp.jsonPath();
log.info("Series Name: " + jp.get("MRData.series").toString().toUpperCase());
log.info("Year: " + jp.get("MRData.CircuitTable.season"));
log.info("Circuit Name: " + jp.get("MRData.CircuitTable.Circuits[0].circuitName"));
log.info("Circuit Country: " + jp.get("MRData.CircuitTable.Circuits[0].Location.country"));
log.info("Total Circuits: " + jp.get("MRData.total"));
log.info("Getting name and country of each circuit -------------------------------------");
for (int i = 0; i < Integer.parseInt(jp.get("MRData.total")); i++) {
log.info("Circuit Name: " + jp.get("MRData.CircuitTable.Circuits[" + i + "].circuitName"));
log.info("Circuit Country: " + jp.get("MRData.CircuitTable.Circuits[" + i + "].Location.country"));
}
}
}
// TestNG Assert library
assertTrue(contentType.toLowerCase().contains("json"));
// assertEquals(contentType, "application/json");
}
// Status Code is of type int
public int getStatusCode(Response response) {
int statusCode;
statusCode = response.getStatusCode();
log.info("Status Code: " + statusCode);
return statusCode;
}
// Status msg is of type string
public String getStatusLine(Response response) {
String statusLine;
statusLine = response.getStatusLine() + "";
log.info("Status Msg: " + statusLine);
return statusLine;
}
public String getHeaderValue(Response response, String headerName) {
String headerValue = "";
headerValue = response.getHeader(headerName) + "";
log.info("Header name: " + headerName + " - value: " + headerValue);
return headerValue;
}
public void getAllHeaders(Response response) {
log.info("Getting value of all Headers via Headers object ---------------------------------");
Headers allHeaders = response.getHeaders();
for (Header header : allHeaders) {
log.info("Header name: " + header.getName() + " - value: " + header.getValue());
}
}
/*
* Keyword sort of methods Invoking requests without first calling the config Req/Resp is successful when common
* spec for response is not used
*/
public void invokeRestNoConfig() {
getURL("f1-api");
getResponseBDD();
}
public static void main(String[] args) {
RESTPoC rd = new RESTPoC();
rd.chkResponseF1API();
rd.chkResponseGoogleBooksAPI();
rd.chkInvalidResponse();
rd.sampleJsonPathExp();
}
}
No comments:
Post a Comment