اختبار عميل REST باستخدام أداة Restito: ما هو Rest Client؟

ما هو ريست؟

REST يرمز إلى "نقل الحالة التمثيلية"، وهي طريقة جديدة للاتصال بين أي نظامين في وقت معين. أحد النظامين يسمى "REST Client"، والآخر يسمى "REST Server".

في هذا البرنامج التعليمي REST، سوف تتعلم:

قبل التعرف على اختبار عميل Restito Framework for REST، دعنا نتعلم أولاً بعض الأساسيات.

ما هو عميل REST؟

REST Client هو طريقة أو أداة لاستدعاء واجهة برمجة تطبيقات خدمة REST التي يتم عرضها للاتصال من قبل أي نظام أو مزود خدمة. على سبيل المثال: إذا تم الكشف عن واجهة برمجة التطبيقات (API) للحصول على معلومات حركة المرور في الوقت الفعلي حول مسار من Google، فإن البرنامج/الأداة التي تستدعي واجهة برمجة تطبيقات حركة مرور Google تسمى عميل REST.

ما هو خادم REST؟

إنها طريقة أو واجهة برمجة تطبيقات (API) قابلة للاتصال من قبل أي نظام أو مزود خدمة. على سبيل المثال، تعرض Google واجهة برمجة التطبيقات (API) للحصول على معلومات حركة المرور في الوقت الفعلي على طريق معين.

هنا، يجب أن يكون خادم Google جاهزًا للعمل للاستماع إلى أي طلبات إلى واجهة برمجة التطبيقات المكشوفة من عملاء مختلفين.

على سبيل المثال:

لقد حان الوقت لإنشاء سيناريو كامل من البداية إلى النهاية من التعريفات المذكورة أعلاه.

دعونا نفكر في تطبيقات حجز سيارات الأجرة مثل Uber حيث تحتاج الشركة إلى معلومات في الوقت الفعلي عن حالة المرور حول الطرق التي تتواجد فيها مركبة معينة.

عميل الراحة:

هنا العميل هو تطبيق Uber للهاتف المحمول الذي قام السائق بتسجيل الدخول إليه. يرسل هذا التطبيق طلبًا إلى REST API الذي تعرضه خرائط Google للحصول على البيانات في الوقت الفعلي. على سبيل المثال، طلب HTTP GET.

خادم الراحة:

في هذا المثال، Google هي مزود الخدمة، وتستجيب واجهة برمجة تطبيقات خرائط Google بالمطلوبtails بناءً على طلب تطبيق أوبر.

كل من العميل والخادم لهما نفس القدر من الأهمية في اتصال REST.

قمنا هنا بتنفيذ أمثلة لاختبار التشغيل الآلي لعميل REST فقط. لاختبار خادم REST، راجع https://www.guru99.com/top-6-api-testing-tool.html.

ما هو ريستيتو؟

Restito هو إطار تم تطويره بواسطة Mkotsur. إنه تطبيق خفيف الوزن يساعدك على تنفيذ أي نوع من طلبات HTTP. يمكنك استخدام Restito لاختبار واجهات برمجة تطبيقات REST الخاصة بك وللبحث عن المشكلات في تطبيقك أو شبكتك.

كيفية اختبار عميل REST باستخدام Restito؟

دعونا نقسم التمرين إلى المتابعةwing 4 خطوات:

  1. قم بإنشاء عميل HTTP وطريقة لإرسال طلب HTTP GET إلى أي نقطة نهاية للخادم. في الوقت الحالي، اعتبر أن نقطة النهاية هي http://localhost:9092/getevents.
  1. ابدأ تشغيل خادم Restito للاستماع والتقاط الطلبات المرسلة إلى نقطة النهاية "getevents" في المضيف المحلي http://localhost:9092/getevents.
  1. قم بإنشاء فئة اختبار لاختبار العميل أعلاه. قم باستدعاء أسلوب عميل HTTP "sendGETRequest" لبدء طلب GET إلى واجهة برمجة التطبيقات "getevents".
  1. التحقق من صحة استدعاء HTTP GET باستخدام إطار عمل Restito.

دعونا نتعمق في كل خطوة من الخطوات المذكورة أعلاه.

الخطوة 1) قم بإنشاء عميل HTTP وطريقة لإرسال طلب HTTP GET إلى أي نقطة نهاية للخادم.

========== يبدأ كود جافا ===========

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;
	}
}

========== ينتهي كود جافا ===========

الخطوة 2) ابدأ تشغيل خادم Restito للاستماع والتقاط الطلبات المرسلة إلى نقطة النهاية "getevents" في المضيف المحلي http://localhost:9092/getevents.

========== يبدأ كود جافا ===========

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


}

========== ينتهي كود جافا ===========

الخطوة 3) قم بإنشاء فئة اختبار لاختبار العميل أعلاه. قم باستدعاء طريقة sendGETRequest لعميل HTTP لبدء طلب GET إلى واجهة برمجة التطبيقات 'getevents'.

========== يبدأ كود جافا ===========

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

========== ينتهي كود جافا ===========

الخطوة 4) كيفية التحقق من صحة طلب GET باستخدام الرؤوس وطلب POST مع الجسم باستخدام إطار عمل Restito.

========== يبدأ كود جافا ===========

/**
     * 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();
            }
		}
	}
}

========== ينتهي كود جافا ===========

مزايا استخدام Restito Framework لاختبار عميل REST

فيما يلي إيجابيات/فوائد Restito Framework لاختبار عميل ReST

  • لا نحتاج إلى تطوير خادم REST الفعلي لاختبار عميل REST.
  • يوفر Restito أدوات مساعدة وأساليب قوية ومتنوعة للسخرية من السلوك المختلف للخادم. على سبيل المثال: لاختبار كيفية تصرف عميل REST عندما يستجيب الخادم بخطأ HTTP 404 أو خطأ HTTP 503.
  • يمكن إعداد خوادم Restito في أجزاء قليلة من الثانية ويمكن إنهاؤها بعد اكتمال الاختبارات.
  • يدعم Restito جميع أنواع محتويات طريقة HTTP مثل المضغوطة وغير المضغوطة والموحدة والتطبيق/النص والتطبيق/JSON وما إلى ذلك.

عيوب استخدام Restito Framework لاختبار عميل REST

فيما يلي سلبيات/عيوب Restito Framework لاختبار عميل ReST

  • يجب تعديل مصدر عميل REST ليعتبر "المضيف المحلي" بمثابة جهاز خادم.
  • قد يتعارض فتح الخادم في أي منفذ إذا استخدمنا بعض المنافذ شائعة الاستخدام مثل "8080" أو "9443" وما إلى ذلك.
  • يُنصح باستخدام منافذ مثل 9092 أو 9099، والتي لا يتم استخدامها بشكل شائع بواسطة الأدوات الأخرى.

ملخص:

  • يرمز REST إلى "نقل الحالة التمثيلية" وهي طريقة قياسية جديدة للاتصال بين أي نظامين في وقت معين.
  • REST Client هو طريقة أو أداة لاستدعاء واجهة برمجة تطبيقات خدمة REST التي تتعرض للاتصال من قبل أي نظام أو مزود خدمة.
  • في طريقة RestServer أو واجهة برمجة التطبيقات (API) التي يتم عرضها للاتصال من قبل أي نظام أو مزود خدمة.
  • Restito هو تطبيق خفيف الوزن يساعدك على تنفيذ أي نوع من طلبات HTTP
  • قم بإنشاء عميل HTTP وطريقة لإرسال طلب HTTP GET إلى أي نقطة نهاية للخادم
  • قم بتشغيل خادم Restito للاستماع والتقاط الطلبات المرسلة إلى نقطة النهاية "getevents".
  • ابدأ تشغيل خادم Restito للاستماع والتقاط الطلبات المرسلة إلى نقطة النهاية "getevents" في المضيف المحلي
  • قمنا هنا بتنفيذ أمثلة لاختبار التشغيل الآلي لعميل REST فقط.
  • لا نحتاج إلى تطوير خادم REST الفعلي لاختبار عميل REST.
  • يجب تعديل مصدر عميل REST ليعتبر "المضيف المحلي" بمثابة جهاز خادم.