Testarea clientului REST folosind Instrumentul Restito: Ce este clientul REST?
Ce este REST?
REST รฎnseamnฤ โTransfer de stat reprezentativโ, care este o nouฤ modalitate de comunicare รฎntre oricare douฤ sisteme la un moment dat. Unul dintre sisteme se numeศte โClient RESTโ, iar celฤlalt se numeศte โServer RESTโ.
รnainte de a afla despre Cadrul Restito pentru testarea clienศilor REST, mai รฎntรขi sฤ รฎnvฤศฤm cรขteva elemente de bazฤ.
Ce este REST Client?
Clientul REST este o metodฤ sau un instrument pentru invocarea unui API de servicii REST expus pentru comunicare de cฤtre orice sistem sau furnizor de servicii. De exemplu: dacฤ un API este expus pentru a obศine informaศii despre trafic รฎn timp real despre o rutฤ de la Google, software-ul/instrumentul care invocฤ Google API-ul de trafic se numeศte client REST.
Ce este REST Server?
Este o metodฤ sau o interfaศฤ de programare a aplicaศiilor (API) expusฤ comunicฤrii de cฤtre orice sistem sau furnizor de servicii. De exemplu, Google expune o API pentru a obศine informaศii despre trafic รฎn timp real pe o anumitฤ rutฤ.
Aici Google Serverul trebuie sฤ fie funcศional pentru a asculta orice solicitฤri cฤtre API-ul expus de la diferiศi clienศi.
Exemplu:
Este timpul sฤ stabilim un scenariu complet End-to-End din definiศiile de mai sus.
Sฤ luฤm รฎn considerare aplicaศiile de rezervare a taxiului precum Uber, deoarece o companie are nevoie de informaศii รฎn timp real despre situaศia traficului รฎn jurul rutelor pe care se aflฤ un anumit vehicul.
Client de odihnฤ:
Aici, clientul este o aplicaศie mobilฤ Uber la care ศoferul s-a conectat. Aceastฤ aplicaศie trimite o solicitare cฤtre API-ul REST expus de Google hฤrศi pentru a obศine date รฎn timp real. De exemplu, o cerere HTTP GET.
Server de odihnฤ:
รn acest exemplu, Google este furnizorul de servicii ศi Google API-ul hฤrศilor rฤspunde cu detaliile necesare la solicitarea aplicaศiei Uber.
Atรขt clientul, cรขt ศi serverul sunt la fel de importante รฎn comunicarea REST.
Aici, am implementat exemple pentru testarea automatฤ numai a clientului REST. Pentru testarea serverului REST, consultaศi https://www.guru99.com/api-testing-tool.html.
Ce este Restito?
Restito este un cadru dezvoltat de Mkotsur. Este o aplicaศie uศoarฤ care vฤ ajutฤ sฤ executaศi orice fel de solicitare HTTP. Puteศi folosi Restito pentru a vฤ testa API-urile REST ศi pentru a cฤuta probleme รฎn aplicaศia dvs. sau รฎn reศea.
Cum se testeazฤ clientul REST folosind Restito?
Sฤ รฎmpฤrศim exerciศiul รฎn urmฤtorii 4 paศi:
- Creaศi un client HTTP ศi o metodฤ pentru a trimite o solicitare HTTP GET cฤtre orice punct final al serverului. Pentru moment, luaศi รฎn considerare punctul final ca fiind
http://localhost:9092/getevents.
- Porniศi un server Restito pentru a asculta ศi captura cererile trimise la punctul final โgeteventsโ รฎn localhost
http://localhost:9092/getevents.
- Creaศi o clasฤ de testare pentru a testa clientul de mai sus. Invocaศi metoda โsendGETRequestโ a clientului HTTP pentru a iniศia o solicitare GET cฤtre API โgeteventsโ.
- Validaศi apelul HTTP GET utilizรขnd cadrul Restito.
Sฤ ne aprofundฤm รฎn fiecare dintre paศii de mai sus.
Pas 1) Creaศi un client HTTP ศi o metodฤ pentru a trimite cererea HTTP GET cฤtre orice punct final al serverului.
========== COD JAVA รncepe ===========
package com.chamlabs.restfulservices.client;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.json.JSONObject;
/**
* This class creates a HTTP Client and has a method to send HTTP GET request:
* sendGETRequest(..)
*/
public class RestClient {
/**
* Constructor for the class RestClient
*/
public RestClient() {
System.out.println("Creating RestClient constructor");
}
/**
* Method to Send GET request to http://localhost:<<port>>/getevents
* @param port
* @return true if GET request is successfully sent. False, otherwise.
*/
public static boolean sendGETRequest(int port) {
try {
HttpClient client = HttpClientBuilder.create().build();
HttpGet getRequest = new HttpGet("http://localhost:" + port + "/getevents");
//HttpResponse response = client.execute(request);
client.execute(getRequest);
System.out.println("HTTP request is sent successfully."
+ "Returning True");
return true;
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Some exception has occurred during the HTTP Client creation."
+ "Returning false");
return false;
}
}
========== COD JAVA se terminฤ ===========
Pas 2) Porniศi un server Restito pentru a asculta ศi captura cererile trimise la punctul final โgeteventsโ รฎn localhost http://localhost:9092/getevents.
========== COD JAVA รncepe ===========
package com.chamlabs.restfultesting.util;
import static com.xebialabs.restito.builder.stub.StubHttp.whenHttp;
import static com.xebialabs.restito.semantics.Action.status;
import static com.xebialabs.restito.semantics.Condition.get;
import static com.xebialabs.restito.semantics.Condition.post;
import java.util.List;
import org.glassfish.grizzly.http.util.HttpStatus;
import com.xebialabs.restito.semantics.Call;
import com.xebialabs.restito.server.StubServer;
/**
* This utility class contains several utility methods like :
* restartRestitoServerForGETRequests(..)
* restartRestitoServerForPOSTRequests(..)
* waitAndGetCallList(..)
*
* @author cham6
* @email: paperplanes.chandra@gmail.com
* @fork: https://github.com/cham6/restfultesting.git
*
*/
public class TestUtil {
/**
* Utility method to start restito stub server to accept GET requests
* @param server
* @param port
* @param status
*/
public static void restartRestitoServerForGETRequests (StubServer server, int port, HttpStatus status)
{
// Kill the restito server
if (server != null) {
server.stop();
}
// Initialize and configure a newer instance of the stub server
server = new StubServer(port).run();
whenHttp(server).match(get("/getevents")).then(status(status));
}
/**
* Utility method to start restito stub server to accept POST requests
* @param server
* @param port
* @param status
*/
public static void restartRestitoServerForPOSTRequests (StubServer server, int port, HttpStatus status)
{
// Kill the restito server
if (server != null) {
server.stop();
}
// Initialize and configure a newer instance of the stub server
server = new StubServer(port).run();
whenHttp(server).match(post("/postevents")).then(status(status));
}
/**
* For a given restito stub server, loop for the given amount of seconds and
* break and return the call list from server.
*
* @param server
* @param waitTimeInSeconds
* @return
* @throws InterruptedException
*/
public static List<Call> waitAndGetCallList (StubServer server, int waitTimeInSeconds)
throws InterruptedException
{
int timeoutCount = 0;
List<Call> callList = server.getCalls();
while (callList.isEmpty()) {
Thread.sleep(1000);
timeoutCount++;
if (timeoutCount >= waitTimeInSeconds) {
break;
}
callList = server.getCalls();
}
// Wait for 2 seconds to get all the calls into callList to Eliminate any falkyness.
Thread.sleep(2000);
return server.getCalls();
}
}
========== COD JAVA se terminฤ ===========
Pas 3) Creaศi o clasฤ de testare pentru a testa clientul de mai sus. Invocaศi metoda client HTTP sendGETRequest pentru a iniศia o solicitare GET cฤtre API โgeteventsโ.
========== COD JAVA รncepe ===========
import junit.framework.TestCase;
import com.chamlabs.restfulservices.client.RestClient;
import com.chamlabs.restfultesting.util.TestUtil;
import com.xebialabs.restito.semantics.Call;
import com.xebialabs.restito.server.StubServer;
import static org.glassfish.grizzly.http.util.HttpStatus.ACCEPTED_202;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
/**
* This class contains several junit tests to validate the RestClient operations like:
* sendRequest(..)
* sendRequestWithCustomHeaders(..)
* sendPOSTRequestWithJSONBody(..)
*
*/
public class RestClientTester extends TestCase {
private static final Integer PORT = 9098;
private static final Integer PORT2 = 9099;
private static final Integer PORT3 = 9097;
public RestClientTester() {
System.out.println("Starting the test RestClientTester");
}
/**
* Junit test to validate the GET request from RestClient
* Steps:
* 1) Create a stub server using Restito framework and configure it to listen on given port
* 2) Invoke the sendGETRequest(..) method of RestClient
* 3) Restito captures the matching GET requests sent, if any.
* 4) Validate if Restito has captured any GET requests on given endpoint
* Expected Behavior:
* > Restito should have captured GET request and it should have captured only one GET request.
* Finally:
* > Stop the stub server started using restito.
*/
public void testGETRequestFromClient() {
StubServer server = null;
try {
//This will start the stub server on 'PORT' and responds with HTTP 202 'ACCEPTED_202'
TestUtil.restartRestitoServerForGETRequests(server, PORT, ACCEPTED_202);
RestClient.sendGETRequest(PORT);
List<Call> callList = TestUtil.waitAndGetCallList(server, 30);
assertTrue("GET request is not received from the RestClient. Test failed.",
(callList != null) && (callList.size() == 1));
}
catch(Exception e) {
e.printStackTrace();
fail("Test Failed due to exception : " + e);
}
finally {
if(server != null) {
server.stop();
}
}
}
========== COD JAVA se terminฤ ===========
Pas 4) Cum se valideazฤ cererea GET cu anteturi ศi cererea POST cu corpul folosind cadrul Restito.
========== COD JAVA รncepe ===========
/**
* Junit test to validate the GET request with headers from RestClient
* Steps:
* 1) Create a stub server using Restito framework and configure it to listen on given port
* 2) Invoke the sendGETRequestWithCustomHeaders(..) method of RestClient
* 3) Restito captures the matching GET requests sent, if any.
* 4) Validate if Restito has captured any GET requests on a given endpoint
* Expected Behavior:
* > Restito should have captured GET request, and it should have captured only one GET request.
* > Get the headers of the captured GET request
* and make sure the headers match to the ones configured.
* Finally:
* > Stop the stub server started using restito.
*/
public void testGETRequestWithHeadersFromClient() {
StubServer server = null;
try {
//This will start the stub server on 'PORT' and responds with HTTP 202 'ACCEPTED_202'
TestUtil.restartRestitoServerForGETRequests(server, PORT2, ACCEPTED_202);
RestClient.sendGETRequestWithCustomHeaders(PORT2);
List<Call> callList = TestUtil.waitAndGetCallList(server, 30);
assertTrue("GET request is not received from the RestClient. Test failed.",
(callList != null) && (callList.size() == 1));
//Validate the headers of the GET request from REST Client
Map<String, List<String>> headersFromRequest = callList.get(0).getHeaders();
assertTrue("GET request contains header Accept and its value ",
headersFromRequest.get("Accept").contains("text/html"));
assertTrue("GET request contains header Authorization and its value ",
headersFromRequest.get("Authorization").contains("Bearer 1234567890qwertyuiop"));
assertTrue("GET request contains header Cache-Control and its value ",
headersFromRequest.get("Cache-Control").contains("no-cache"));
assertTrue("GET request contains header Connection and its value ",
headersFromRequest.get("Connection").contains("keep-alive"));
assertTrue("GET request contains header Content-Type and its value ",
headersFromRequest.get("Content-Type").contains("application/json"));
}
catch(Exception e) {
e.printStackTrace();
fail("Test Failed due to exception : " + e);
}
finally {
if(server != null) {
server.stop();
}
}
}
/**
* Junit test to validate the POST request with body and headers from RestClient
* Steps:
* 1) Create a stub server using Restito framework and configure it to listen on given port
* 2) Invoke the sendPOSTRequestWithJSONBody(..) method of RestClient
* 3) Restito captures the matching POST requests sent, if any.
* 4) Validate if Restito has captured any POST requests on given endpoint
* Expected Behavior:
* > Restito should have captured POST request and it should have captured only one POST request.
* > Get the body of the captured POST request and validate the JSON values
* Finally:
* > Stop the stub server started using restito.
*/
public void testPOSTRequestWithJSONBody() {
StubServer server = null;
try {
//This will start the stub server on 'PORT' and responds with HTTP 202 'ACCEPTED_202'
TestUtil.restartRestitoServerForPOSTRequests(server, PORT3, ACCEPTED_202);
RestClient.sendPOSTRequestWithJSONBody(PORT3);
List<Call> callList = TestUtil.waitAndGetCallList(server, 30);
assertTrue("POST request is not received from the RestClient. Test failed.",
(callList != null) && (callList.size() == 1));
//Validate the headers of the GET request from REST Client
String requestBody = callList.get(0).getPostBody();
JSONObject postRequestJSON = new JSONObject(requestBody);
assertTrue("The timeUpdated in json is incorrect",
postRequestJSON.get("timeUpdated").toString().equalsIgnoreCase("1535703838478"));
assertTrue("The access_token in json is incorrect",
postRequestJSON.get("access_token").toString().
equalsIgnoreCase("abf8714d-73a3-42ab-9df8-d13fcb92a1d8"));
assertTrue("The refresh_token in json is incorrect",
postRequestJSON.get("refresh_token").toString().
equalsIgnoreCase("d5a5ab08-c200-421d-ad46-2e89c2f566f5"));
assertTrue("The token_type in json is incorrect",
postRequestJSON.get("token_type").toString().equalsIgnoreCase("bearer"));
assertTrue("The expires_in in json is incorrect",
postRequestJSON.get("expires_in").toString().equalsIgnoreCase("1024"));
assertTrue("The scope in json is incorrect",
postRequestJSON.get("scope").toString().equalsIgnoreCase(""));
}
catch(Exception e) {
e.printStackTrace();
fail("Test Failed due to exception : " + e);
}
finally {
if(server != null) {
server.stop();
}
}
}
}
========== COD JAVA se terminฤ ===========
Avantajele utilizฤrii cadrului Restito pentru testarea clientului REST
Iatฤ avantajele/beneficiile Cadrului Restito pentru testarea clienศilor ReST
- Nu avem nevoie ca serverul REST sฤ fie dezvoltat pentru a testa clientul REST.
- Restito oferฤ utilitฤศi ศi metode puternice ศi variate pentru a bate joc de comportamentul diferit al unui server. De exemplu: pentru a testa modul รฎn care clientul REST se comportฤ atunci cรขnd Serverul rฤspunde cu eroare HTTP 404 sau eroare HTTP 503.
- Serverele Restito pot fi configurate รฎn cรขteva milisecunde ศi pot fi terminate dupฤ finalizarea testelor.
- Restito acceptฤ toate tipurile de conศinut al metodei HTTP, cum ar fi comprimat, necomprimat, unificat, aplicaศie/text, aplicaศie/JSON etc.
Dezavantajele utilizฤrii cadrului Restito pentru testarea clientului REST
Iatฤ dezavantajele/dezavantajele cadrului Restito pentru testarea clienศilor ReST
- Sursa clientului REST ar trebui sฤ fie ajustatฤ pentru a considera โlocalhostโ ca o maศinฤ server.
- Deschiderea serverului รฎn orice port poate intra รฎn conflict dacฤ folosim un port folosit รฎn mod obiศnuit, cum ar fi โ8080โ sau โ9443โ etc.
- Este recomandat sฤ utilizaศi porturi precum 9092 sau 9099, care nu sunt utilizate รฎn mod obiศnuit de alte instrumente.
Rezumat
- REST รฎnseamnฤ โRepresentational State Transferโ, care este un nou mod standard de comunicare รฎntre oricare douฤ sisteme la un moment dat.
- Clientul REST este o metodฤ sau un instrument de invocare a unui serviciu API REST care este expus comunicฤrii de cฤtre orice sistem sau furnizor de servicii.
- รn metoda RestServer sau un API care este expus pentru comunicare de cฤtre orice sistem sau furnizor de servicii.
- Restito este o aplicaศie uศoarฤ care vฤ ajutฤ sฤ executaศi orice fel de solicitare HTTP
- Creaศi un client HTTP ศi o metodฤ pentru a trimite o solicitare HTTP GET cฤtre orice punct final al serverului
- Porniศi un server Restito pentru a asculta ศi captura cererile trimise cฤtre punctul final โgeteventsโ.
- Porniศi un server Restito pentru a asculta ศi captura cererile trimise la punctul final โgeteventsโ รฎn localhost
- Aici, am implementat exemple pentru testarea automatฤ numai a clientului REST.
- Nu avem nevoie ca serverul REST sฤ fie dezvoltat pentru a testa clientul REST.
- Sursa clientului REST ar trebui sฤ fie ajustatฤ pentru a considera โlocalhostโ ca o maศinฤ server.
