Restito Aracını Kullanarak REST İstemci Testi: Rest Client Nedir?
REST nedir?
DİNLENME Belirli bir zamanda herhangi iki sistem arasında yeni bir iletişim yolu olan “Temsili Durum Transferi” anlamına gelir. Sistemlerden birine 'REST Client', diğerine ise 'REST Server' adı veriliyor.
REST istemci testi için Restito Framework'ü öğrenmeden önce birkaç temel bilgiyi öğrenelim.
REST İstemcisi nedir?
REST İstemcisi, herhangi bir sistem veya hizmet sağlayıcı tarafından iletişime açık olan bir REST hizmeti API'sini çağırmak için kullanılan bir yöntem veya araçtır. Örneğin: bir API, Google'dan bir rota hakkında gerçek zamanlı trafik bilgisi almak üzere kullanıma sunulursa, Google trafik API'sini çağıran yazılıma/araca REST istemcisi adı verilir.
REST Sunucusu Nedir?
Herhangi bir sistem veya servis sağlayıcı tarafından iletişime açık olan bir yöntem veya API'dir. Örneğin Google, belirli bir rotadaki gerçek zamanlı trafik bilgilerini almak için bir API sunar.
Burada, farklı istemcilerden gelen açık API isteklerini dinlemek için Google sunucusunun çalışır durumda olması gerekir.
Örnek:
Yukarıdaki tanımlardan eksiksiz bir Uçtan Uca senaryo oluşturmanın zamanı geldi.
Bir şirketin, belirli bir aracın bulunduğu güzergahlardaki trafik durumu hakkında gerçek zamanlı bilgiye ihtiyacı olması nedeniyle Uber gibi taksi rezervasyon uygulamalarını ele alalım.
Dinlenme İstemcisi:
Burada istemci, sürücünün oturum açtığı bir Uber mobil uygulamasıdır. Bu uygulama, gerçek zamanlı verileri almak için Google haritalarının sunduğu REST API'sine bir istek gönderir. Örneğin, bir HTTP GET isteği.
Dinlenme Sunucusu:
Bu örnekte, Google Servis sağlayıcıdır ve Google Haritalar'ın API'si, Uber uygulamasının isteğine gerekli ayrıntılarla yanıt verir.
REST iletişiminde hem istemci hem de sunucu eşit derecede önemlidir.
Burada yalnızca REST İstemcisinin otomasyon testi için örnekler uyguladık. REST sunucusunu test etmek için bkz. https://www.guru99.com/top-6-api-testing-tool.html.
Restito nedir?
Restito, Mkotsur tarafından geliştirilen bir framework'tür. Herhangi bir HTTP İsteğini yürütmenize yardımcı olan hafif bir uygulamadır. Restito'yu REST API'lerinizi test etmek ve uygulamanızdaki veya ağınızdaki sorunları aramak için kullanabilirsiniz.
Restito kullanarak REST istemcisi nasıl test edilir?
Egzersizi aşağıdaki 4 adıma bölelim:
- Herhangi bir sunucu uç noktasına HTTP GET isteği göndermek için bir HTTP istemcisi ve yöntemi oluşturun. Şimdilik uç noktayı düşünün
http://localhost:9092/getevents
.
- Localhost'taki 'getevents' uç noktasına gönderilen istekleri dinlemek ve yakalamak için bir Restito sunucusu başlatın
http://localhost:9092/getevents
.
- Yukarıdaki istemciyi test etmek için bir test sınıfı oluşturun. 'Getevents' API'sine bir GET isteği başlatmak için HTTP istemcisi 'sendGETRequest' yöntemini çağırın.
- Restito çerçevesini kullanarak HTTP GET çağrısını doğrulayın.
Yukarıdaki adımların her birine derinlemesine dalalım.
) 1 Adım Herhangi bir sunucu uç noktasına HTTP GET isteği göndermek için bir HTTP istemcisi ve yöntemi oluşturun.
========== JAVA KODU Başlıyor ===========
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; } }
========== JAVA KODU Biter ===========
) 2 Adım Localhost'taki 'getevents' uç noktasına gönderilen istekleri dinlemek ve yakalamak için bir Restito sunucusu başlatın http://localhost:9092/getevents
.
========== JAVA KODU Başlıyor ===========
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(); } }
========== JAVA KODU Biter ===========
) 3 Adım Yukarıdaki istemciyi test etmek için bir test sınıfı oluşturun. 'Getevents' API'sine bir GET isteği başlatmak için HTTP istemcisi sendGETRequest yöntemini çağırın.
========== JAVA KODU Başlıyor ===========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(); } } }
========== JAVA KODU Biter ===========
) 4 Adım Restito çerçevesini kullanarak GET isteğini Başlıklarla ve POST isteğini gövdeyle doğrulama.
========== JAVA KODU Başlıyor ===========
/** * 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(); } } } }
========== JAVA KODU Biter ===========
REST istemci testi için Restito Framework'ü kullanmanın avantajları
ReST istemci testi için Restito Framework'ün artıları/faydaları şunlardır
- REST İstemcisini test etmek için gerçek REST sunucusunun geliştirilmesine ihtiyacımız yok.
- Restito, bir Sunucunun farklı davranışlarını taklit etmek için güçlü ve çeşitli yardımcı programlar ve yöntemler sağlar. Örneğin: Sunucu HTTP 404 hatası veya HTTP 503 hatasıyla yanıt verdiğinde REST istemcisinin nasıl davrandığını test etmek.
- Restito sunucuları birkaç milisaniye içerisinde kurulabilir ve testler tamamlandıktan sonra sonlandırılabilir.
- Restito, sıkıştırılmış, sıkıştırılmamış, birleştirilmiş, uygulama/metin, uygulama/JSON vb. gibi her türlü HTTP yöntemi içeriğini destekler.
REST istemci testi için Restito Framework kullanmanın dezavantajları
İşte ReST istemci testi için Restito Framework'ün eksileri/dezavantajları
- REST istemci kaynağı, 'localhost'u bir sunucu makinesi olarak değerlendirecek şekilde ayarlanmalıdır.
- '8080' veya '9443' gibi yaygın olarak kullanılan bazı bağlantı noktalarını kullanırsak, sunucuyu herhangi bir bağlantı noktasında açmak çakışmaya neden olabilir.
- Diğer araçlar tarafından yaygın olarak kullanılmayan 9092 veya 9099 gibi portların kullanılması tavsiye edilir.
ÖZET
- REST, belirli bir zamanda herhangi iki sistem arasında yeni bir standart iletişim yolu olan “Temsili Durum Transferi” anlamına gelir.
- REST İstemcisi, herhangi bir sistem veya hizmet sağlayıcı tarafından iletişime açık olan bir REST hizmeti API'sini çağırmak için kullanılan bir yöntem veya araçtır.
- RestServer yönteminde veya herhangi bir sistem veya servis sağlayıcı tarafından iletişime açık olan bir API'de.
- Restito, her türlü HTTP İsteğini yürütmenize yardımcı olacak hafif bir uygulamadır
- Herhangi bir sunucu uç noktasına HTTP GET isteği göndermek için bir HTTP istemcisi ve yöntemi oluşturun
- 'Getevents' uç noktasına gönderilen istekleri dinlemek ve yakalamak için bir Restito sunucusu başlatın.
- Localhost'taki 'getevents' uç noktasına gönderilen istekleri dinlemek ve yakalamak için bir Restito sunucusu başlatın
- Burada yalnızca REST İstemcisinin otomasyon testi için örnekler uyguladık.
- REST İstemcisini test etmek için gerçek REST sunucusunun geliştirilmesine ihtiyacımız yok.
- REST istemci kaynağı, 'localhost'u bir sunucu makinesi olarak değerlendirecek şekilde ayarlanmalıdır.