使用 Restito 工具进行 REST 客户端测试:什么是 Rest 客户端?
什么是休息?
REST的 代表“表述性状态转移”,这是任意两个系统在给定时间点之间进行通信的一种新方式。其中一个系统称为“REST 客户端”,另一个系统称为“REST 服务器”。
在了解用于 REST 客户端测试的 Restito 框架之前,让我们先学习一些基础知识。
什么是 REST 客户端?
REST 客户端是一种调用 REST 服务 API 的方法或工具,该 API 由任何系统或服务提供商公开用于通信。例如:如果公开了 API 来从 Google 获取有关路线的实时交通信息,则调用 Google 交通 API 的软件/工具称为 REST 客户端。
什么是 REST 服务器?
它是任何系统或服务提供商向通信公开的一种方法或 API。例如,Google 公开了一个 API 来获取给定路线的实时交通信息。
这里,Google 服务器需要启动并运行,以监听来自不同客户端对公开 API 的任何请求。
示例:
现在是时候根据上述定义建立一个完整的端到端场景了。
让我们考虑一个像 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 是什么?
Restito 是由 Mkotsur 开发的框架。它是一款轻量级应用程序,可帮助您执行任何类型的 HTTP 请求。您可以使用 Restito 测试您的 REST API 并搜索应用程序或网络中的问题。
如何使用 Restito 测试 REST 客户端?
让我们将练习分为以下 4 个步骤:
- 创建 HTTP 客户端和方法,向任意服务器端点发送 HTTP GET 请求。目前,考虑将端点设为
http://localhost:9092/getevents
.
- 启动 Restito 服务器来监听并捕获发送到 localhost 中端点“getevents”的请求
http://localhost:9092/getevents
.
- 创建一个测试类来测试上述客户端。调用 HTTP 客户端“sendGETRequest”方法向 API“getevents”发起 GET 请求。
- 使用 Restito 框架验证 HTTP GET 调用。
让我们深入了解上述每个步骤。
步骤1) 创建一个 HTTP 客户端和方法,向任何服务器端点发送 HTTP GET 请求。
========== JAVA CODE 开始 ===========
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 CODE 结束 ===========
步骤2) 启动 Restito 服务器来监听并捕获发送到 localhost 中端点“getevents”的请求 http://localhost:9092/getevents
.
========== JAVA CODE 开始 ===========
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 CODE 结束 ===========
步骤3) 创建一个测试类来测试上述客户端。调用 HTTP 客户端 sendGETRequest 方法向 API“getevents”发起 GET 请求。
========== JAVA CODE 开始 ===========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 CODE 结束 ===========
步骤4) 如何使用 Restito 框架验证带有标头的 GET 请求以及带有正文的 POST 请求。
========== JAVA CODE 开始 ===========
/** * 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 CODE 结束 ===========
使用 Restito Framework 进行 REST 客户端测试的优势
以下是 Restito Framework 用于 ReST 客户端测试的优点/好处
- 我们不需要开发实际的 REST 服务器来测试 REST 客户端。
- Restito 提供强大而多样的实用程序和方法来模拟服务器的不同行为。例如:测试当服务器响应 HTTP 404 错误或 HTTP 503 错误时 REST 客户端的行为。
- Restito 服务器可以在几毫秒内设置完毕,并可以在测试完成后终止。
- Restito 支持所有类型的 HTTP 方法内容,如压缩、非压缩、统一、应用程序/文本、应用程序/JSON 等。
使用 Restito Framework 进行 REST 客户端测试的缺点
以下是 Restito Framework 用于 ReST 客户端测试的缺点/不足之处
- 应该调整 REST 客户端源以将“localhost”视为服务器。
- 如果我们使用一些常用端口(如“8080”或“9443”等),则在任何端口打开服务器都可能会发生冲突。
- 建议使用 9092 或 9099 等端口,其他工具不常用这些端口。
总结
- REST 代表“表述性状态转移”,它是在给定时间点任意两个系统之间进行通信的新标准方式。
- REST 客户端是一种调用任何系统或服务提供商公开给通信的 REST 服务 API 的方法或工具。
- 在 RestServer 方法或由任何系统或服务提供商公开用于通信的 API 中。
- Restito 是一款轻量级应用程序,可帮助你执行任何类型的 HTTP 请求
- 创建 HTTP 客户端和方法,向任意服务器端点发送 HTTP GET 请求
- 启动 Restito 服务器来监听并捕获发送到端点“getevents”的请求。
- 启动 Restito 服务器来监听并捕获发送到 localhost 中端点“getevents”的请求
- 在这里,我们仅实现了 REST 客户端的自动化测试示例。
- 我们不需要开发实际的 REST 服务器来测试 REST 客户端。
- 应该调整 REST 客户端源以将“localhost”视为服务器。