如何使用Rest Assured进行RESTful API测试
本文最后更新于:2024年11月22日 下午 04:43:14
RESTful API
随着互联网和移动设备的发展,人们对Web应用的使用需求也增加,传统的动态页面(如JSP)由于低效率而渐渐被HTML+JavaScript(Ajax)的前后端分离所取代,并且安卓、IOS、小程序等形式客户端层出不穷,客户端的种类出现多元化,而客户端和服务端就需要接口进行通信,但接口的规范性是一个问题。
所以一套结构清晰、符合标准、易于理解、扩展方便让大部分人都能够理解接受的接口风格就显得越来越重要,而RESTful风格的接口(RESTful API)刚好有以上特点,就逐渐被实践应用而变得流行起来,可以参考GitHub REST API documentation - GitHub Docs的文档对REST API进行学习。
REST并没有一个明确的标准,而更像是一种设计的风格,满足这种设计风格的程序或接口我们称之为RESTful(从单词字面来看就是一个形容词)。所以RESTful API 就是满足REST架构风格的接口。如果用一句话大概概括一下REST风格,那就是URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。 此处只简单介绍REST API,因为这不是讨论的重点,关于REST API设计规范和限制条件,需要在日常开发中了解学习。
HTTP请求方法和状态码
REST API使用五种HTTP方法来发送请求:
- GET:在特定的URL上检索信息。
- PUT:如果资源存在,则更新先前的资源,若不存在,则创建新的信息。
- POST:向服务器发送信息,例如上传数据或创建新的实体。
- DELETE:删除特定URL上的所有当前资源。
- PATCH:用于对资源进行部分更新。
当使用以上方法发送请求后,客户端会收到数字形式的代码,称为“状态码”,有时也叫“响应码”。然后我们可以根据这些状态码来解读服务器对特定请求发送的响应。状态码主要分为五类,具体如下:
- 1xx(100-199):信息,服务器收到请求,需要请求者继续执行操作
- 2xx(200-299):成功,操作被成功接收并处理
- 3xx(300-399):重定向,需要进一步的操作以完成请求
- 4xx(400-499):客户端错误,请求包含语法错误或无法完成请求
- 5xx(500-599):服务器错误,服务器在处理请求的过程中发生了错误,无法完成请求
通过以上状态码,我们可以判断应用程序的运行情况。1xx、2xx和3xx状态码通常不被视为错误,而是提供了一些信息性的消息,它们并不会影响用户体验。
但是,如果收到了4xx或5xx状态码,则表示发生了错误。这意味着用户/APP在访问API时可能会遇到错误消息。4xx状态码通常与客户端或浏览器级别的错误相关,而5xx状态码通常表示服务器级别的错误。因此在进行REST API测试时,应该通过检查这些错误代码来评估每个响应的情况。
有关HTTP协议的具体内容细节,可以查阅。HTTP | MDN (mozilla.org)
示例
以toolsqa网站的一个demo作为例子,我们可以在这里Swagger UI (demoqa.com)看到该示例提供的一些API,这个例子是一个书店的库存管理系统,提供了多种REST API方法来获取书店中书的信息。
Swagger 是一个实现了OpenAPI 规范的工具集,SwaggerUI是其生成的文档/页面。
在SwaggerUI中我们还可以对接口进行执行,这里的GET方法返回的是Books的具体内容。
使用Rest Assured进行REST API测试
Rest Assured是一个Java库,用于测试RESTful API。它被广泛应用于测试基于JSON和XML的Web应用程序。此外,它完全支持GET、PUT、POST、PATCH和DELETE等所有REST方法。接下来详细介绍如何使用Rest Assured库测试一个REST API。
要编写一个示例的REST API测试,我们将使用以下REST API链接。
HTTP方法:GET
备注:此URL将返回书店的库存详情。请求中没有输入参数。
响应:{“books”: [{“isbn”: “string”,”title”: “string”,”subTitle”: “string”,”author”:”string”,”publish_date”: “2022-01-25T13:44:50.276Z”,”publisher”: “string”,”pages”: 0,”description”: “string”,”website”: “string”}]}
实际上,如果我们直接在浏览器中打开上述URL,我们会得到如下所示的输出:
要使用Rest Assured库以编程方式获取相同的输出,我们需要按照以下步骤操作:
- 使用RestAssured类生成一个针对URL的RequestSpecification。
- 指定HTTP方法类型(GET方法)。
- 将请求发送到服务器。
- 从服务器获取响应。
- 打印返回的响应体。
以下是执行以上步骤的示例代码:
1 |
|
这样一来,我们就能够发起测试 API 调用,并从对应的接口获取响应了。
现在我们来简单说明一下对应的代码:
1 |
|
上述代码使用 RestAssured 类来设定基本 URI。在这里,基本 URI 是 “https://demoqa.com/BookStore/v1/Books”。基本 URI 指示了我们即将从服务器请求的资源的根地址(因此称为基本 URI)。然后,当我们在随后的代码中实际发起请求时,我们会添加参数(如果有的话)。
io.restassured.RestAssured 类是我们进行测试时所发起的任何类型的 HTTP 请求的基础。该类的一些关键特性包括:
- 使用基本 URI 生成 HTTP 请求。
- 提供支持以创建不同的 HTTP 方法类型(GET、POST、PUT、PATCH、DELETE、UPDATE、HEAD 和 OPTIONS)的请求。
- 使用 HTTP 与服务器进行通信,并将测试中创建的请求发送到服务器。
- 接收来自服务器的响应。
- 提供支持验证从服务器接收到的响应。
- io.restassured.RestAssured类内部使用了一个基于 Groovy 语言的 HTTP 客户端 HTTP builder 库。
1 |
|
接下来的代码获取了要发送到服务器的请求的RequestSpecification对象。Rest Assured库提供了名为RequestSpecification的接口,用于此目的。变量httpRequest存储了请求,以便我们可以在需要时修改它,比如添加身份验证信息、添加头部等。在这个示例测试中,我们没有对该变量进行修改。
现在,我们调用接口以获取资源,以上代码使用request方法向服务器发送资源请求。
request方法接受两个参数,第一个是HTTP方法,第二个是一个字符串。字符串参数用于指定要与基本URI一起发送的参数。在这种情况下,为了获取Books的详情,我们不发送任何参数,因此使用了空字符串。request方法的返回类型是Response对象,这意味着request方法从服务器获取了响应并且把结果存在response这个实例中。
Response接口(io.restassured.response.Response)表示从服务器返回的响应。它包含服务器发送的所有数据。接下来的例子中可以调用此响应对象上的不同方法来提取响应,例如响应状态、header等。
1 |
|
在上述代码行中,我们将响应作为字符串读取,并将其打印到System.out。我们使用响应接口的getBody方法返回响应的body。然后将其打印到System.out。
我们也可以使用Rest Assured提供的简写方法来编写上述测试代码。以下是稍微简化了的代码段。
1 |
|
在这里使用了RequestSpecification对象上的“get”方法,该方法向接口发送了一个GET方法,返回Response对象。
使用Rest Assured验证HTTP响应状态
每个客户端发送到服务器的HTTP请求都会收到一个HTTP响应,其中包含一个状态码。这个状态码告诉我们HTTP响应是否成功。其中我们进行了一个示例的REST API测试调用。接下来将讨论如何使用REST Assured来验证HTTP响应的状态。
一个HTTP响应对象通常代表了Web服务服务器发回的HTTP数据包(响应数据包),作为对客户端请求的响应。一个HTTP响应包含状态、header、body这几个部分。当我们说需要验证HTTP响应状态时,我们希望有一种机制来读取和验证整个响应对象,包括状态、header、body,需要验证HTTP响应的每个组成部分。
同一个REST API会以XML或JSON格式返回响应消息,格式取决于HTTP请求中的Media-Type属性。那么客户端如何知道它将从API获得什么类型的响应呢?这是由响应头来管理的。响应头包含一个Content-Type属性,用于通知响应主体格式的类型。
假设我们通过浏览器向图书商店发送GET请求,如下所示:
1 |
|
执行上述命令,结果如下:
如图,响应头中包含一个content-type属性,还有一些其他的属性值。通过解析这个头部,客户端就知道可以期待什么类型的响应(body)。
当客户端从服务器请求特定信息时,服务器会向客户端发送一个带有状态码的响应。服务器返回的状态码告诉我们请求是否成功。如果请求成功,服务器会在200-299的范围内发送状态码。如果请求未成功,则返回不在该范围内的状态码。
Rest Assured库提供了一个名为”io.restassured.response”的包,其中包含一个Response接口。Response接口提供了一些方法,可以帮助获取接收到的响应的各个部分。
其中方法 getStatusCode() 用于获取响应的状态码。该方法返回一个int,然后我们可以验证其值,这里使用TestNG Assert 用于验证状态码,代码如下:
1 |
|
下面的代码用于获取状态码:
1 |
|
返回值 “statusCode” 被与期望值即 200 进行比较。如果两个值相等,则返回相应的消息或者打印正确的log。
1 |
|
通过这种方式,我们可以使用响应接口的 “getStatusCode()” 方法来验证响应的状态码,这是一种比较常见的场景,即接口返回成功的状态码2xx。接下来让我们讨论如何验证返回值不是 200(即错误状态码)的状态码,这也是另一种对接口的常见测试场景。
在实际的测试场景中可能存在诸如服务器宕机、REST API 不正常运行或请求本身存在问题等原因。总之,我们可能会遇到以下几种情况:
- 服务器宕机。
- 客户端请求不正确。
- 客户端请求的资源不存在。
- 在处理请求时服务器端发生错误。
当出现以上任何情况时,REST API 将返回一个错误状态码,客户端必须根据此状态码进行相应的处理。对之前给出的Demo链接,创建另一个测试,来模拟一个错误的场景。在这里,我们将验证当输入无效参数时, Web 服务返回的 HTTP 状态码。
我们提供参数以获取用户详细信息。这里我们提供了不存在的 userId 作为参数。代码如下:
1 |
|
运行这个测试,因为返回的状态码和预期的期望是相同的,所以测试通过。
除了对状态码进行验证,我们还可以验证完整的状态行及其中包含的其他消息,”状态行” 是 HTTP 响应中返回的第一行,由三个子字符串组成:
- HTTP 协议版本。
- 状态码。
- 状态码的字符串值。
例如,当请求成功时,状态行将具有值 “HTTP/1.1 200 OK”。这里,第一部分是 HTTP 协议(HTTP/1.1)。接下来是 HTTP 状态码(200)。第三部分是状态消息(OK)。
我们可以使用响应接口的 getStatusLine()
方法来读取整个状态行。以下代码是一个简单的例子:
1 |
|
在这里,我们执行了类似于对状态码的测试。我们使用 getStatusLine()
方法读取状态行,并将其存储在字符串值中。然后,我们将此返回值与 “HTTP/1.1 200 OK” 进行比较,以检查状态是否成功。
对于header的检验大致和对于状态码的检验相同,不过header的检验更多用的是字符串相关的校验方法,此处不做详细说明。
对于body的检验比较复杂,后续根据实际场景再填充内容。
//TODO