A Guide to REST-assured – REST-保证的指南

最后修改: 2016年 7月 24日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

REST-assured was designed to simplify the testing and validation of REST APIs and is highly influenced by testing techniques used in dynamic languages such as Ruby and Groovy.

REST-assured旨在简化REST API的测试和验证,并受到Ruby和Groovy等动态语言中使用的测试技术的高度影响。

The library has solid support for HTTP, starting of course with the verbs and standard HTTP operations, but also going well beyond these basics.

该库对HTTP有坚实的支持,当然从动词和标准的HTTP操作开始,但也远远超出了这些基础知识。

In this guide, we are going to explore REST-assured and we’re going to use Hamcrest to do assertion. If you are not already familiar with Hamcrest, you should first brush up with the tutorial: Testing with Hamcrest.

在本指南中,我们将探索REST-assured,我们将使用Hamcrest来做论断。如果你还不熟悉Hamcrest,你应该先学习一下这个教程。用Hamcrest进行测试

Also, to learn about more advanced use-cases of REST-assured, check out our other articles:

此外,要了解REST-保证的更多高级用例,请查看我们的其他文章。

Now let’s dive in with a simple example.

现在让我们通过一个简单的例子来深入了解。

2. Simple Example Test

2.简单的测试实例

Before we get started, let’s ensure that our tests have the following static imports:

在我们开始之前,让我们确保我们的测试有以下静态导入。

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*

We’ll need that to keep tests simple and have easy access to the main APIs.

我们需要这一点来保持测试的简单性,并能方便地访问主要的API。

Now, let’s get started with the simple example – a basic betting system exposing some data for games:

现在,让我们从简单的例子开始–一个基本的投注系统暴露了一些游戏的数据。

{
    "id": "390",
    "data": {
        "leagueId": 35,
        "homeTeam": "Norway",
        "visitingTeam": "England",
    },
    "odds": [{
        "price": "1.30",
        "name": "1"
    },
    {
        "price": "5.25",
        "name": "X"
    }]
}

Let’s say that this is the JSON response from hitting the locally deployed API – http://localhost:8080/events?id=390. :

比方说,这是点击本地部署的API的JSON响应 – http://localhost:8080/events?id=390。

Let’s now use REST-assured to verify some interesting features of the response JSON:

现在让我们使用REST-assured来验证响应JSON的一些有趣的特征。

@Test
public void givenUrl_whenSuccessOnGetsResponseAndJsonHasRequiredKV_thenCorrect() {
   get("/events?id=390").then().statusCode(200).assertThat()
      .body("data.leagueId", equalTo(35)); 
}

So, what we did here is – we verified that a call to the endpoint /events?id=390 responds with a body containing a JSON String whose leagueId of the data object is 35.

所以,我们在这里所做的是–我们验证了对端点/events?id=390的调用,响应了一个包含JSON字符串的主体,其leagueIddata对象为35。

Let’s have a look at a more interesting example. Let’s say you would like to verify that the odds array has records with prices 1.30 and 5.25:

让我们来看看一个更有趣的例子。假设你想验证odds数组中有价格1.305.25的记录。

@Test
public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() {
   get("/events?id=390").then().assertThat()
      .body("odds.price", hasItems("1.30", "5.25"));
}

3. REST-assured Setup

3.REST-保证的设置

If your favorite dependency tool is Maven, we add the following dependency in the pom.xml file:

如果你喜欢的依赖工具是Maven,我们在pom.xml文件中添加以下依赖。

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>

To get the latest version, follow this link.
REST-assured takes advantage of the power of Hamcrest matchers to perform its assertions, so we must include that dependency as well:

要获得最新版本,请遵循这个链接
REST-assured利用Hamcrest匹配器的力量来执行其断言,所以我们也必须包括这个依赖。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>2.1</version>
</dependency>

The latest version will always be available at this link.

最新版本将始终在这个链接上提供。

4. Anonymous JSON Root Validation

4.匿名的JSON根部验证

Consider an array that comprises of primitives rather than objects:

考虑一个由基元而非对象组成的数组。

[1, 2, 3]

This is called an anonymous JSON root, meaning that it has no key-value pair nevertheless it is still valid JSON data.

这被称为匿名JSON根,意味着它没有键值对,但它仍然是有效的JSON数据。

We can run validation in such a scenario by using the $ symbol or an empty String ( “” ) as path. Assume we expose the above service through http://localhost:8080/json then we can validate it like this with REST-assured:

我们可以通过使用$符号或空字符串(””)作为路径在这种情况下运行验证。假设我们通过http://localhost:8080/json公开上述服务,那么我们可以像这样用REST-assured来验证它。

when().get("/json").then().body("$", hasItems(1, 2, 3));

or like this:

或像这样。

when().get("/json").then().body("", hasItems(1, 2, 3));

5. Floats and Doubles

5.浮动和双打

When we start using REST-assured to test our REST services, we need to understand that floating point numbers in JSON responses are mapped to primitive type float.

当我们开始使用REST-assured来测试我们的REST服务时,我们需要了解JSON响应中的浮点数字被映射到原始类型float.

The use of float type is not interchangeable with double as is the case for many scenarios in java.

使用float类型不能与double互换,在java中的许多情况下都是如此。

Case in point is this response:

这方面的例子是这个答复。

{
    "odd": {
        "price": "1.30",
        "ck": 12.2,
        "name": "1"
    }
}

assume we are running the following test on the value of ck:

假设我们对ck的值运行以下测试。

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2));

This test will fail even if the value we are testing is equal to the value in the response. This is because we are comparing to a double rather than to a float.

即使我们测试的值与响应中的值相等,这个测试也会失败。这是因为我们是与double而不是与float进行比较。

To make it work, we have to explicitly specify the operand to the equalTo matcher method as a float, like so:

为了使其发挥作用,我们必须明确地将equalTo匹配器方法的操作数指定为float,像这样。

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f));

6. Specifying the Request Method

6.指定请求方法

Typically, we would perform a request by calling a method such as get(), corresponding to the request method we want to use.

通常,我们会通过调用诸如get()的方法来执行请求,对应于我们想要使用的请求方法。

In addition, we can also specify the HTTP verb using the request() method:

此外,我们还可以使用request()方法指定HTTP动词

@Test
public void whenRequestGet_thenOK(){
    when().request("GET", "/users/eugenp").then().statusCode(200);
}

The example above is equivalent to using get() directly.

上面的例子等同于直接使用get()

Similarly, we can send HEAD, CONNECT and OPTIONS requests:

同样地,我们可以发送HEADCONNECTOPTIONS请求。

@Test
public void whenRequestHead_thenOK() {
    when().request("HEAD", "/users/eugenp").then().statusCode(200);
}

POST request also follows a similar syntax and we can specify the body by using the with() and body() methods.

POST请求也遵循类似的语法,我们可以通过使用with()body()方法来指定主体

Therefore, to create a new Odd by sending a POST request:

因此,通过发送POST请求来创建一个新的Odd

@Test
public void whenRequestedPost_thenCreated() {
    with().body(new Odd(5.25f, 1, 13.1f, "X"))
      .when()
      .request("POST", "/odds/new")
      .then()
      .statusCode(201);
}

The Odd object sent as body will automatically be converted to JSON. We can also pass any String that we want to send as our POST body.

作为body发送的Odd对象将被自动转换为JSON。我们也可以传递任何我们想要发送的String作为我们的POSTbody

7. Default Values Configuration

7.默认值配置

We can configure a lot of default values for the tests:

我们可以为测试配置很多的默认值。

@Before
public void setup() {
    RestAssured.baseURI = "https://api.github.com";
    RestAssured.port = 443;
}

Here, we’re setting a base URI and port for our requests. Besides these, we can also configure the base path, root pat, and authentication.

在这里,我们要为我们的请求设置一个基本URI和端口。除了这些,我们还可以配置基本路径、根补丁和认证。

Note: we can also reset to the standard REST-assured defaults by using:

注意:我们也可以通过使用重置为标准的REST保证的默认值。

RestAssured.reset();

8. Measure Response Time

8.测量响应时间

Let’s see how we can measure the response time using the time() and timeIn() methods of the Response object:

让我们看看如何使用Response对象的time()timeIn()方法来测量响应时间。

@Test
public void whenMeasureResponseTime_thenOK() {
    Response response = RestAssured.get("/users/eugenp");
    long timeInMS = response.time();
    long timeInS = response.timeIn(TimeUnit.SECONDS);
    
    assertEquals(timeInS, timeInMS/1000);
}

Note that:

请注意,。

  • time() is used to get response time in milliseconds
  • timeIn() is used to get response time in the specified time unit

8.1. Validate Response Time

8.1.验证响应时间

We can also validate the response time – in milliseconds – with the help of simple long Matcher:

我们还可以在简单的long Matcher:的帮助下验证响应时间–以毫秒为单位。

@Test
public void whenValidateResponseTime_thenSuccess() {
    when().get("/users/eugenp").then().time(lessThan(5000L));
}

If we want to validate the response time in a different time unit, then we’ll use the time() matcher with a second TimeUnit parameter:

如果我们想用不同的时间单位来验证响应时间,那么我们将使用带有第二个TimeUnit参数的time()匹配器。

@Test
public void whenValidateResponseTimeInSeconds_thenSuccess(){
    when().get("/users/eugenp").then().time(lessThan(5L),TimeUnit.SECONDS);
}

9. XML Response Verification

9.XML响应验证

Not only can it validate a JSON response, itcan validate XML as well.

它不仅可以验证JSON响应,还可以验证XML。

Let’s assume we make a request to http://localhost:8080/employees and we get the following response:

让我们假设我们向http://localhost:8080/employees发出请求,并得到以下响应。

<employees>
    <employee category="skilled">
        <first-name>Jane</first-name>
        <last-name>Daisy</last-name>
        <sex>f</sex>
    </employee>
</employees>

We can verify that the first-name is Jane like so:

我们可以验证first-nameJane像这样。

@Test
public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() {
    post("/employees").then().assertThat()
      .body("employees.employee.first-name", equalTo("Jane"));
}

We can also verify that all values match our expected values by chaining body matchers together like so:

我们也可以通过这样将主体匹配器串联起来,验证所有的值是否符合我们的预期值。

@Test
public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() {
    post("/employees").then().assertThat()
      .body("employees.employee.first-name", equalTo("Jane"))
        .body("employees.employee.last-name", equalTo("Daisy"))
          .body("employees.employee.sex", equalTo("f"));
}

Or using the shorthand version with variable arguments:

或者使用带有可变参数的速记版本。

@Test
public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() {
    post("/employees")
      .then().assertThat().body("employees.employee.first-name", 
        equalTo("Jane"),"employees.employee.last-name", 
          equalTo("Daisy"), "employees.employee.sex", 
            equalTo("f"));
}

10. XPath for XML

10.XML的XPath

We can also verify our responses using XPath. Consider the example below that executes a matcher on the first-name:

我们还可以使用XPath来验证我们的响应。考虑下面的例子,在first-name上执行一个匹配器。

@Test
public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() {
    post("/employees").then().assertThat().
      body(hasXPath("/employees/employee/first-name", containsString("Ja")));
}

XPath also accepts an alternate way of running the equalTo matcher:

XPath也接受运行equalTo匹配器的另一种方式。

@Test
public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() {
    post("/employees").then().assertThat()
      .body(hasXPath("/employees/employee/first-name[text()='Jane']"));
}

11. Logging Test Details

11.记录测试细节

11.1. Log Request Details

11.1.日志请求详情

First, let’s see how to log entire request details using log().all():

首先,让我们看看如何使用log().all()来记录整个请求的细节:

@Test
public void whenLogRequest_thenOK() {
    given().log().all()
      .when().get("/users/eugenp")
      .then().statusCode(200);
}

This will log something like this:

这将记录类似这样的内容。

Request method:	GET
Request URI:	https://api.github.com:443/users/eugenp
Proxy:			<none>
Request params:	<none>
Query params:	<none>
Form params:	<none>
Path params:	<none>
Multiparts:		<none>
Headers:		Accept=*/*
Cookies:		<none>
Body:			<none>

To log only specific parts of the request, we have the log() method in combination with params(), body(), headers(), cookies(), method(), path() eg log.().params().

为了只记录请求的特定部分,我们有log()方法与params(), body(), headers(), cookies(), method(), path()相结合,例如log.

Note that other libraries or filters used may alter what’s actually sent to the server, so this should only be used to log the initial request specification.

注意,所使用的其他库或过滤器可能会改变实际发送到服务器的内容,所以这只应该被用来记录最初的请求规范。

11.2. Log Response Details

11.2.日志响应细节

Similarly, we can log the response details.

同样地,我们可以记录响应的细节。

In the following example we’re logging the response body only:

在下面的例子中,我们只记录响应主体。

@Test
public void whenLogResponse_thenOK() {
    when().get("/repos/eugenp/tutorials")
      .then().log().body().statusCode(200);
}

Sample output:

样本输出。

{
    "id": 9754983,
    "name": "tutorials",
    "full_name": "eugenp/tutorials",
    "private": false,
    "html_url": "https://github.com/eugenp/tutorials",
    "description": "The \"REST With Spring\" Course: ",
    "fork": false,
    "size": 72371,
    "license": {
        "key": "mit",
        "name": "MIT License",
        "spdx_id": "MIT",
        "url": "https://api.github.com/licenses/mit"
    },
...
}

11.3. Log Response if Condition Occurred

11.3.条件发生时的日志响应

We also have the option of logging the response only if an error occurred or the status code matches a given value:

我们还可以选择只在发生错误或状态代码与给定值相匹配时记录响应。

@Test
public void whenLogResponseIfErrorOccurred_thenSuccess() {
 
    when().get("/users/eugenp")
      .then().log().ifError();
    when().get("/users/eugenp")
      .then().log().ifStatusCodeIsEqualTo(500);
    when().get("/users/eugenp")
      .then().log().ifStatusCodeMatches(greaterThan(200));
}

11.4. Log if Validation Failed

11.4.验证失败时的日志

We can also log both request and response only if our validation failed:

如果我们的验证失败,我们也可以同时记录请求和响应。

@Test
public void whenLogOnlyIfValidationFailed_thenSuccess() {
    when().get("/users/eugenp")
      .then().log().ifValidationFails().statusCode(200);

    given().log().ifValidationFails()
      .when().get("/users/eugenp")
      .then().statusCode(200);
}

In this example, we want to validate that the status code is 200. Only if this fails, the request and response will be logged.

在这个例子中,我们要验证状态代码是否为200。只有当这一点失败时,请求和响应才会被记录下来。

12. Conclusion

12.结论

In this tutorial, we have explored the REST-assured framework and looked at its most important features which we can use to test our RESTful services and validate their responses.

在本教程中,我们已经探索了REST-assured框架,并查看了其最重要的功能,我们可以用它来测试我们的RESTful服务并验证其响应。

The full implementation of all these examples and code snippets can be found in the REST-assured GitHub project.

所有这些例子和代码片段的完整实现可以在REST-assured GitHub项目中找到