Тестування клієнта REST за допомогою інструменту Restito: що таке клієнт Rest?

Що таке ВІДПОЧИНОК?

REST означає «REpresentational State Transfer», що є новим способом зв’язку між будь-якими двома системами в певний момент часу. Одна із систем називається «REST Client», а інша — «REST Server».

Перш ніж дізнатися про Restito Framework для тестування клієнта REST, давайте спершу вивчимо кілька основ.

Що таке клієнт REST?

Клієнт REST — це метод або інструмент для виклику API служби REST, відкритий для зв’язку будь-якою системою чи постачальником послуг. Наприклад: якщо API надається для отримання інформації про трафік у реальному часі щодо маршруту від Google, програмне забезпечення/інструмент, який викликає API трафіку Google, називається клієнтом REST.

Що таке сервер REST?

Це метод або API, який доступний будь-якій системі чи постачальнику послуг. Наприклад, Google надає API для отримання інформації про дорожній рух на певному маршруті в реальному часі.

Тут сервер Google має бути запущеним, щоб прослуховувати будь-які запити до відкритого API від різних клієнтів.

приклад:

Настав час створити повний наскрізний сценарій з наведених вище визначень.

Давайте розглянемо такі додатки для замовлення таксі, як Uber, оскільки компанії потрібна інформація в режимі реального часу про дорожню ситуацію на маршрутах, на яких знаходиться даний транспортний засіб.

Rest Client:

Тут клієнтом є мобільний додаток Uber, до якого водій увійшов. Ця програма надсилає запит до REST API, який відкривають карти Google, щоб отримати дані в реальному часі. Наприклад, запит HTTP GET.

Rest Server:

У цьому прикладі Google є постачальником послуг, а API карт Google відповідає необхідними деталями на запит програми Uber.

І клієнт, і сервер є однаково важливими для спілкування REST.

Тут ми реалізували приклади для автоматизованого тестування лише клієнта REST. Щоб перевірити сервер REST, див https://www.guru99.com/top-6-api-testing-tool.html.

Що таке Restito?

Restito — це фреймворк, розроблений Mkotsur. Це легка програма, яка допоможе вам виконати будь-який HTTP-запит. Ви можете використовувати Restito для тестування ваших REST API і для пошуку проблем у вашій програмі чи мережі.

Як перевірити клієнт REST за допомогою Restito?

Давайте розділимо вправу на наступні 4 етапи:

  1. Створіть клієнт HTTP та метод для надсилання запиту HTTP GET на будь-яку кінцеву точку сервера. Поки що кінцевою точкою буде http://localhost:9092/getevents.
  1. Запустіть сервер Restito для прослуховування та захоплення запитів, надісланих до кінцевої точки 'getevents' у localhost http://localhost:9092/getevents.
  1. Створіть тестовий клас для тестування вищезазначеного клієнта. Викличте метод клієнта HTTP «sendGETRequest», щоб ініціювати запит GET до API «getevents».
  1. Перевірте виклик HTTP GET за допомогою Restito framework.

Давайте глибше зануримося в кожен із наведених вище кроків.

Крок 1) Створіть клієнт HTTP та метод для надсилання запиту HTTP GET на будь-яку кінцеву точку сервера.

========== КОД JAVA Запускається ============

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 Закінчується ============

Крок 2) Запустіть сервер Restito для прослуховування та захоплення запитів, надісланих до кінцевої точки 'getevents' у localhost http://localhost:9092/getevents.

========== КОД JAVA Запускається ============

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 Закінчується ============

Крок 3) Створіть тестовий клас для тестування вищезазначеного клієнта. Викличте метод sendGETRequest клієнта HTTP, щоб ініціювати запит GET до API «getevents».

========== КОД JAVA Запускається ============
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 Закінчується ============

Крок 4) Як перевірити запит GET із заголовками та запит POST із тілом за допомогою фреймворку Restito.

========== КОД JAVA Запускається ============

/**
     * 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 Закінчується ============

Переваги використання 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 слід налаштувати, щоб «localhost» розглядався як сервер.
  • Відкриття сервера в будь-якому порту може конфліктувати, якщо ми використовуємо якийсь часто використовуваний порт, наприклад «8080» або «9443» тощо.
  • Рекомендується використовувати такі порти, як 9092 або 9099, які зазвичай не використовуються іншими інструментами.

Підсумки

  • REST означає «REpresentational State Transfer», що є новим стандартним способом зв’язку між будь-якими двома системами в певний момент часу.
  • Клієнт REST — це метод або інструмент для виклику API служби REST, який доступний будь-якій системі чи постачальнику послуг.
  • У методі RestServer або API, який доступний для зв’язку будь-якою системою чи постачальником послуг.
  • Restito — це легка програма, яка допоможе вам виконати будь-який HTTP-запит
  • Створіть клієнт HTTP та метод для надсилання запиту HTTP GET на будь-яку кінцеву точку сервера
  • Запустіть сервер Restito для прослуховування та захоплення запитів, надісланих до кінцевої точки "getevents".
  • Запустіть сервер Restito для прослуховування та захоплення запитів, надісланих до кінцевої точки 'getevents' у localhost
  • Тут ми реалізували приклади для автоматизованого тестування лише клієнта REST.
  • Для тестування клієнта REST нам не потрібно розробляти фактичний сервер REST.
  • Клієнтське джерело REST слід налаштувати, щоб «localhost» розглядався як сервер.