使用Restito工具进行REST客户端测试

REST是什么?

REST是任意两个系统在给定时间点之间的一种新的通信方式。其中一个系统叫做“REST客户端”,另一个叫做“REST服务器”。

在本REST教程中,将了解:

  • REST是什么?
  • 什么是REST客户端?
  • 什么是REST服务器?
  • Restito是什么?
  • 如何使用Restito测试REST客户端?
  • 使用Restito框架进行REST客户端测试的优势
  • 使用Restito框架进行REST客户端测试的缺点

在了解REST客户端测试的Restito框架之前,让我们先了解一些基础知识。

什么是REST客户端?

REST客户端是调用REST服务api的方法或工具,任何系统或服务提供商都会公开该方法或工具进行通信。例如:如果一个应用编程接口被暴露为从高德获取路线的实时交通信息,那么调用高德交通应用编程接口的软件/工具称为REST客户端。

什么是REST服务器?

REST服务器是公开给任何系统或服务提供商通信的方法或API。例如,高德公开了一个API来获取给定路线的实时交通信息。

在这里,高德服务器需要启动并运行,才能监听来自不同客户端对公开的API的任何求。

示例:

现在是时候根据上述定义建立完整的端到端场景了。考虑像滴滴这样的出租车预订应用程序,因为公司需要关于给定车辆所在路线周围的交通状况的实时信息。

REST客户端:

这里的客户端是驱动程序登录的滴滴移动应用程序。例如,此应用程序发送HTTP GET求。

REST服务器:

在本例中,高德是服务提供商,高德Maps的API使用滴滴应用程序求所需的详细信息进行响应。

在REST通信中,客户端和服务器同等重要。

Restito是什么?

Restito是Mkotsur开发的框架。这是一个轻量级的应用程序,可以使用Restito来测试RESTAPI,并搜索应用程序或网络中的问题。

如何使用Restito测试REST客户端?

练习以下4个步骤:

  1. 创建一个HTTP客户端和方法以将HTTP GET求发送到任何服务器端点。目前,将端点视为http://localhost:9092/getevents.

  2. 启动Restito服务器以侦听和捕获发送到本地主机http://localhost:9092/getevents中的端点“getevents”的求。

  3. 创建一个测试类来测试上述客户端。调用HTTP客户端的‘sendGETRequest’方法向接口‘getevents’发起GET求。

  4. 使用Restito框架验证HTTP GET调用。

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

步骤2) 启动Restito服务器,监听并捕获发送到本地主机http://localhost:9092/getevents中的端点‘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) 创建测试类对上述客户端进行测试。调用HTTP客户端sendGETRequest方法发起对‘getevents’接口的GET求。

 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框架验证带Header的GET求和带Body的POST求。

 /
* 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框架进行REST客户端测试的优势

以下是用于REST客户端测试的Restito框架的优点/优点

  • 不需要开发实际的REST服务器来测试REST客户端。
  • Restito提供强大而多样的实用程序和方法来模拟服务器的不同行为。例如:测试当服务器响应HTTP404错误或HTTP503错误时REST客户端的行为。
  • Restito服务器可以在几毫秒内设置好,并且可以在测试完成后终止。
  • Restito支持所有类型的HTTP方法内容,如压缩、非压缩、统一、应用/文本、应用/JSON等。

使用Restito框架进行REST客户端测试的缺点

下面是Restito框架在REST客户端测试中的优缺点

  • 应该对REST客户端源进行调整,以将“localhost”视为服务器计算机。
  • 如果我们使用一些常用的端口,如‘8080’或‘9443’等,在任何端口打开服务器都可能会发生冲突。
  • 使用9092或9099等其他工具不常用的端口。

总结:

  • REST是一种在给定时间点任何两个系统之间进行通信的新标准方式。
  • REST客户端是调用REST服务api的方法或工具,任何系统或服务提供商都可以使用该方法或工具进行通信。
  • 在RestServer方法或任何系统或服务提供商为通信而公开的API中。
  • Restito是一款轻量级应用程序,可以帮助执行任何类型的HTTP求
  • 创建HTTP客户端和方法以将HTTP GET求发送到任何服务器端点
  • 启动Restito服务器以侦听和捕获发送到端点“getevent”的求。
  • 启动Restito服务器以侦听和捕获发送到localhost中的端点“getevents”的求
  • 在这里,我们只实现了REST客户端的自动化测试示例。
  • 我们不需要开发实际的REST服务器来测试REST客户端。
  • 应该对REST客户端源进行调整,以将“localhost”视为服务器计算机。

IT赶路人

专注IT知识分享