2.8.19

Testing APIs with RestAssured

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();

}

}

No comments:

Post a Comment