Restito 도구를 사용한 REST 클라이언트 테스트: Rest 클라이언트란 무엇입니까?

REST 란 무엇입니까?

REST "REpresentational State Transfer"의 약자로, 특정 시점에 두 시스템 간의 새로운 통신 방식입니다. 그 중 하나는 'REST 클라이언트'이고, 다른 하나는 'REST 서버'이다.

REST 클라이언트 테스트를 위한 Restito Framework에 대해 알아보기 전에 먼저 몇 가지 기본 사항을 알아보겠습니다.

REST 클라이언트란 무엇입니까?

REST 클라이언트는 모든 시스템 또는 서비스 공급자가 통신을 위해 노출하는 REST 서비스 API를 호출하는 방법 또는 도구입니다. 예를 들어 Google의 경로에 대한 실시간 교통 정보를 얻기 위해 API가 노출된 경우 Google 트래픽 API를 호출하는 소프트웨어/도구를 REST 클라이언트라고 합니다.

REST 서버란 무엇입니까?

시스템이나 서비스 공급자의 통신에 노출되는 메서드 또는 API입니다. 예를 들어 Google은 특정 경로에 대한 실시간 교통 정보를 얻기 위해 API를 공개합니다.

여기서는 다양한 클라이언트에서 노출된 API에 대한 요청을 수신하려면 Google 서버가 실행 중이어야 합니다.

예:

이제 위의 정의를 바탕으로 완전한 End-to-End 시나리오를 구축할 차례입니다.

회사에서는 특정 차량이 위치한 경로 주변의 교통 상황에 대한 실시간 정보가 필요하므로 Uber와 같은 택시 예약 애플리케이션을 고려해 보겠습니다.

나머지 클라이언트:

여기서 클라이언트는 운전자가 로그인한 Uber 모바일 애플리케이션입니다. 이 앱은 실시간 데이터를 얻기 위해 Google 지도에 노출된 REST API에 요청을 보냅니다. 예를 들어 HTTP GET 요청입니다.

나머지 서버:

이 예에서 Google은 서비스 제공자이고 Google 지도 API는 Uber 앱의 요청에 필요한 세부 정보를 담아 응답합니다.

REST 통신에서는 클라이언트와 서버 모두 똑같이 중요합니다.

여기서는 REST 클라이언트만의 자동화 테스트를 위한 예제를 구현했습니다. REST 서버를 테스트하려면 다음을 참조하세요. https://www.guru99.com/top-6-api-testing-tool.html.

레스티토란 무엇인가요?

Restito는 Mkotsur에서 개발한 프레임워크입니다. 모든 종류의 HTTP 요청을 실행하는 데 도움이 되는 가벼운 앱입니다. Restito를 사용하여 REST API를 테스트하고 애플리케이션이나 네트워크의 문제를 검색할 수 있습니다.

Restito를 사용하여 REST 클라이언트를 테스트하는 방법은 무엇입니까?

이 연습을 다음의 4단계로 나누어 보겠습니다.

  1. 모든 서버 끝점에 HTTP GET 요청을 보내는 HTTP 클라이언트 및 메서드를 만듭니다. 지금은 엔드포인트를 다음과 같이 고려하세요. http://localhost:9092/getevents.
  1. Restito 서버를 시작하여 localhost의 'getevents' 엔드포인트로 전송된 요청을 수신하고 캡처합니다. http://localhost:9092/getevents.
  1. 위 클라이언트를 테스트하기 위한 테스트 클래스를 만듭니다. HTTP 클라이언트 'sendGETRequest' 메소드를 호출하여 API 'getevents'에 대한 GET 요청을 시작합니다.
  1. Restito 프레임워크를 사용하여 HTTP GET 호출을 검증합니다.

위의 각 단계를 자세히 살펴보겠습니다.

단계 1) 모든 서버 끝점에 HTTP GET 요청을 보내는 HTTP 클라이언트 및 메서드를 만듭니다.

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

========== 자바 코드 끝 ===========

단계 2) Restito 서버를 시작하여 localhost의 'getevents' 엔드포인트로 전송된 요청을 수신하고 캡처합니다. 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();
    }


}

========== 자바 코드 끝 ===========

단계 3) 위 클라이언트를 테스트하기 위한 테스트 클래스를 만듭니다. HTTP 클라이언트 sendGETRequest 메소드를 호출하여 API 'getevents'에 대한 GET 요청을 시작합니다.

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

========== 자바 코드 끝 ===========

단계 4) Restito 프레임워크를 사용하여 헤더가 있는 GET 요청과 본문이 있는 POST 요청을 검증하는 방법.

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

========== 자바 코드 끝 ===========

REST 클라이언트 테스트에 Restito Framework를 사용할 때의 이점

ReST 클라이언트 테스트를 위한 Restito Framework의 장점/이점은 다음과 같습니다.

  • REST 클라이언트를 테스트하기 위해 실제 REST 서버를 개발할 필요는 없습니다.
  • Restito는 서버의 다양한 동작을 모의하기 위한 강력하고 다양한 유틸리티와 방법을 제공합니다. 예를 들어: 서버가 HTTP 404 오류 또는 HTTP 503 오류로 응답할 때 REST 클라이언트가 어떻게 동작하는지 테스트합니다.
  • Restito 서버는 몇 밀리초 안에 설정될 수 있으며 테스트가 완료된 후 종료될 수 있습니다.
  • Restito는 압축, 비압축, 통합, 애플리케이션/텍스트, 애플리케이션/JSON 등 모든 유형의 HTTP 메소드 컨텐츠를 지원합니다.

REST 클라이언트 테스트를 위해 Restito Framework를 사용할 때의 단점

ReST 클라이언트 테스트를 위한 Restito Framework의 단점/단점은 다음과 같습니다.

  • REST 클라이언트 소스는 'localhost'를 서버 시스템으로 간주하도록 조정되어야 합니다.
  • '8080' 또는 '9443' 등과 같이 일반적으로 사용되는 포트를 사용하는 경우 모든 포트에서 서버를 열면 충돌이 발생할 수 있습니다.
  • 다른 도구에서는 일반적으로 사용되지 않는 9092 또는 9099와 같은 포트를 사용하는 것이 좋습니다.

요약

  • REST는 "REpresentational State Transfer"의 약자로 특정 시점에 두 시스템 간의 새로운 통신 표준 방식입니다.
  • REST 클라이언트는 모든 시스템 또는 서비스 공급자의 통신에 노출되는 REST 서비스 API를 호출하는 방법 또는 도구입니다.
  • 모든 시스템 또는 서비스 공급자가 통신을 위해 노출하는 RestServer 메서드 또는 API에서.
  • Restito는 모든 종류의 HTTP 요청을 실행하는 데 도움이 되는 경량 앱입니다.
  • 모든 서버 끝점에 HTTP GET 요청을 보내는 HTTP 클라이언트 및 메서드 만들기
  • Restito 서버를 시작하여 'getevents' 엔드포인트로 전송된 요청을 수신하고 캡처합니다.
  • Restito 서버를 시작하여 localhost의 'getevents' 엔드포인트로 전송된 요청을 수신하고 캡처합니다.
  • 여기서는 REST 클라이언트만의 자동화 테스트를 위한 예제를 구현했습니다.
  • REST 클라이언트를 테스트하기 위해 실제 REST 서버를 개발할 필요는 없습니다.
  • REST 클라이언트 소스는 'localhost'를 서버 시스템으로 간주하도록 조정되어야 합니다.