如何使用REST Assured Java测试POST请求进行API测试:第一部分
REST Assured是Java中流行的API测试自动化框架。软件团队广泛使用它来以最少的设置有效验证RESTful Web服务。它简化了发送请求、验证响应和处理JSON或XML负载的过程。
凭借其丰富的语法和对TestNG和Maven等工具的支持,REST Assured支持健壮、可维护和可扩展的API测试。
在本教程中,您将学习以下内容:
- 使用REST Assured设置Maven项目进行API测试自动化
- 什么是POST请求?
- 如何使用REST Assured Java测试POST请求
开始之前
在开始使用REST Assured编写API测试之前,请确保您的环境已正确设置。您需要在机器上安装和配置以下先决条件:
- Java JDK 17或更高版本
- Apache Maven
- IntelliJ IDE(社区版)或类似的IDE用于编写测试脚本
创建新项目
让我们按照以下步骤创建一个新的Maven项目:
步骤1:打开IntelliJ,然后导航到File » New » Project
步骤2:在"New Project"窗口中输入以下详细信息:
- 项目名称
- 项目保存的位置/路径
- 选择JDK版本(我使用JDK 17)
- Archetype(搜索"quickstart"并从结果中选择maven-archetype-quickstart)
点击"Create"按钮创建项目。
Maven项目将在指定位置成功创建。
更新依赖项
创建项目后,应将以下依赖项和插件添加到pom.xml文件中:
- REST Assured
- TestNG
- Lombok(用于使用构建器模式并在运行时生成POJO)
- Jackson Databind
- Google Gson(用于序列化)
- Datafaker(用于在运行时生成测试数据)
- Hamcrest(用于断言)
- Maven Surefire插件
- Maven Compiler插件
添加所需依赖项和插件后,您的pom.xml文件应如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.mfaisalkhatri</groupId>
<artifactId>rest-assured-examples</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<rest-assured.version>5.5.6</rest-assured.version>
<testng.version>7.11.0</testng.version>
<lombok.version>1.18.42</lombok.version>
<jackson-databind.version>2.20.0</jackson-databind.version>
<google-gson.version>2.13.2</google-gson.version>
<data-faker.version>2.5.1</data-faker.version>
<hamcrest-all.version>1.3</hamcrest-all.version>
<maven-compiler-plugin.version>3.14.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.5.4</maven-surefire-plugin.version>
<java-release.version>17</java-release.version>
<suite-xml>test-suite/testng.xml</suite-xml>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>${data-faker.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${google-gson.version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>${hamcrest-all.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java-release.version}</release>
<encoding>UTF-8</encoding>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>${suite-xml}</suiteXmlFile>
</suiteXmlFiles>
<argLine>-Dfile.encoding=UTF-8 -Xdebug -Xnoagent</argLine>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
|
在<properties>块中更新依赖版本被认为是最佳实践,因为它允许您轻松管理、检查和更新项目中的Maven依赖版本。
将依赖项添加到pom.xml文件后,设置完成,项目现在可以开始使用REST Assured进行API自动化测试。
什么是POST请求?
POST请求用于通过向请求体中发送数据在服务器上创建新资源。这些数据可以采用各种格式,例如JSON、XML或表单数据。
Content-Type头指定正在使用的格式。POST请求不是幂等的,这意味着多次发送相同的请求可能导致服务器上的重复条目或更改。
让我们以RESTful电子商务应用程序中的POST /addOrder API为例。
此POST /addOrder API向服务器发送数据以在系统中创建新订单。当POST请求成功执行时,系统中会生成所需的订单数据。服务器响应201状态码,以及消息和新创建的订单的详细信息。
如何使用REST Assured Java测试POST请求
POST请求需要以所需格式发送请求体;否则,POST请求将无法创建所需结果。
使用REST Assured框架有五种不同的方式发布请求体:
- 字符串
- JSON对象/数组
- 使用POJO
- 使用JSON文件
- 使用构建器模式和运行时DataFaker
让我们逐一使用这些方式编写测试。
1. 使用字符串作为请求体编写POST API测试
这是测试POST API的最简单方法,因为它涉及在字符串格式中对请求体使用硬编码值。这种方法应仅用于临时场景,并在实际项目中避免。
POST /addOrder API在JSON格式中使用以下请求体:
1
2
3
4
5
6
7
8
9
10
11
|
[
{
"user_id": "string",
"product_id": "string",
"product_name": "string",
"product_amount": 0,
"qty": 0,
"tax_amt": 0,
"total_amt": 0
}
]
|
让我们创建一个带有值的硬编码字符串,并将其用作POST请求的请求体。
1
|
String order = "[{\"user_id\": \"1\"," + "\"product_id\": \"1\"," + "\"product_name\": \"iPhone\"," + "\"product_amount\": 500.00," + "\"qty\": 1," + "\"tax_amt\": 5.99," + "\"total_amt\": 505.99}]";
|
让我们创建一个名为TestPostRequestWithHardCodedBody的新Java类,并在其中添加一个新的测试方法testCreateOrder()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class TestPostRequestWithHardCodedBody {
@Test
public void testCreateOrder () {
String order = "[{\"user_id\": \"1\"," + "\"product_id\": \"1\"," + "\"product_name\": \"iPhone\"," + "\"product_amount\": 500.00," + "\"qty\": 1," + "\"tax_amt\": 5.99," + "\"total_amt\": 505.99}]";
given ().contentType (ContentType.JSON)
.when ()
.log ()
.all ()
.body (order)
.post ("http://localhost:3004/addOrder")
.then ()
.log ()
.all ()
.statusCode (201)
.and ()
.assertThat ()
.body ("message", equalTo ("Orders added successfully!"));
}
}
|
代码详解
REST Assured库提供了一个领域特定语言(DSL),使编写API测试变得简单、可读和表达性强。REST Assured支持方法链,允许使用流畅的API风格,提高可读性并使测试脚本更简洁。
POST API测试脚本以given()方法开始,这是given-when-then模式的一部分。given方法配置请求的先决条件。可以配置详细信息,例如头、内容类型、查询参数、身份验证等。
接下来,内容类型用于指定发送到服务器的请求体的媒体类型。通过将内容类型设置为JSON,您告诉服务器请求体中的数据格式化为JavaScript对象表示法(JSON)。
提供内容类型很重要,因为服务器应该知道如何解析传入数据。如果未提供内容类型,服务器可能拒绝请求或误解数据,导致测试失败。
在when()方法之后使用的log().all()方法记录所有请求详细信息,包括发送到服务器的头、参数、身份验证、内容类型和其他数据。这对于调试失败的测试特别有用。
请求体在body()方法中提供,最后使用post()方法执行post请求。body()方法和post()方法一起工作以发送带有请求负载的POST请求。此测试使用字符串格式的硬编码请求体在系统中创建新订单。
在then()方法之后的log().all()方法记录所有响应详细信息,包括头、响应数据和响应内容类型。
断言
REST Assured提供了一个强大的内联断言库,允许您直接在测试脚本中验证响应数据。使用其流畅的语法,您可以轻松验证状态码、响应头和特定的JSON或XML值,而无需额外的断言框架。
statusCode()方法验证状态码为201。还可以通过使用and()和assertThat()方法组合断言,并调用带有预期和实际数据验证所需参数的body()方法来验证响应数据。
在body方法内部调用的equalTo()方法属于Hamcrest库,这是一个在Java中编写可读和表达性强断言的流行框架。
测试执行
以下是IntelliJ IDE中成功测试执行的截图:
以下是控制台中显示请求和响应详细信息的日志:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
Request method: POST
Request URI: http://localhost:3004/addOrder
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: <none>
Path params: <none>
Headers: Accept=*/*
Content-Type=application/json
Cookies: <none>
Multiparts: <none>
Body:
[
{
"user_id": "1",
"product_id": "1",
"product_name": "iPhone",
"product_amount": 500.00,
"qty": 1,
"tax_amt": 5.99,
"total_amt": 505.99
}
]
HTTP/1.1 201 Created
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 178
ETag: W/"b2-cCuoDUhklBnDdnS/dk3LEyOpViA"
Date: Thu, 09 Oct 2025 14:05:50 GMT
Connection: keep-alive
Keep-Alive: timeout=5
{
"message": "Orders added successfully!",
"orders": [
{
"id": 1,
"user_id": "1",
"product_id": "1",
"product_name": "iPhone",
"product_amount": 500,
"qty": 1,
"tax_amt": 5.99,
"total_amt": 505.99
}
]
}
|
2. 使用JSON数组/JSON对象作为请求体编写POST API测试
请求体可以根据要求作为JSON数组或JSON对象提供。有两种方法可以创建JSON请求体。
第一种方法使用Google Gson库创建JSON对象,然后将其添加到JSON数组,形成订单数组,如POST /addOrder API所需。
使用Google Gson为POST请求创建请求体
让我们创建一个新的Java类TestPostRequestWithJsonArray,并创建一个testCreateOrder方法来实现测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class TestPostRequestWithJsonArray {
@Test
public void testCreateOrder () {
JsonObject orderOne = new JsonObject ();
orderOne.addProperty ("user_id", "1");
orderOne.addProperty ("product_id", "1");
orderOne.addProperty ("product_name", "MacBook Pro");
orderOne.addProperty ("product_amount", 9998.23);
orderOne.addProperty ("qty", 1);
orderOne.addProperty ("tax_amt", 999.8);
orderOne.addProperty ("total_amt", 10998.03);
JsonArray orderArray = new JsonArray ();
orderArray.add (orderOne);
given ().contentType (ContentType.JSON)
.when ()
.log ()
.all ()
.body (orderArray.toString ())
.post ("http://localhost:3004/addOrder")
.then ()
.log ()
.all ()
.statusCode (201)
.and ()
.assertThat ()
.body ("message", equalTo ("Orders added successfully!"));
}
}
|
来自Google Gson库的JsonObject类被实例化以创建表示单个订单的新JSON对象。使用addProperty()方法,添加键值对,如user_id、product_name和total_amt等,以定义订单详细信息。
完全构建JSON对象后,使用add()方法将其添加到JsonArray实例。这允许在单个JSON数组中分组多个订单对象,然后可以在API调用中作为请求体发送。
这里应注意,body参数应作为orderArray.toString()传递,因为REST Assured默认使用Jackson库进行JSON序列化,它不知道如何序列化com.google.gson.JsonObject或JsonArray对象。建议使用toString()方法将JSON数组或对象转换为字符串,然后将其传递给body方法。
使用Java集合为POST请求创建请求体
Java集合中的List和Map接口也可用于生成JSON请求负载。如果您不想使用任何第三方库,这很方便。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@Test
public void testCreateOrderWithCollections () {
Map<String, Object> orderOne = new HashMap<> ();
orderOne.put ("user_id", "2");
orderOne.put ("product_id", "2");
orderOne.put ("product_name", "Xiaomi Pad 7");
orderOne.put ("product_amount", 899.67);
orderOne.put ("qty", 1);
orderOne.put ("tax_amt", 89.96);
orderOne.put ("total_amt", 989.63);
List<Map<String, Object>> orderList = new ArrayList<> ();
orderList.add (orderOne);
given ().contentType (ContentType.JSON)
.when ()
.log ()
.all ()
.body (orderList)
.post ("http://localhost:3004/addOrder")
.then ()
.log ()
.all ()
.statusCode (201)
.and ()
.assertThat ()
.body ("message", equalTo ("Orders added successfully!"));
}
|
订单的请求体包含一个由多个JSON对象组成的JSON数组,每个JSON对象表示用于更新订单的详细信息。订单详细信息映射在包含订单详细信息的键值对(如user_id、product_id、product_name、total_amt等)的HashMap中。
然后使用ArrayList将订单详细信息包装在JSON数组中,最后在测试中提供给REST Assured的body()方法。
3. 使用POJO作为请求体编写POST API测试
请求体也可以使用POJO(Plain Old Java Object)传递。这是一种更方便的方法,因为我们编写一次POJO类并在需要时重用它们。进一步,这些POJO还可以与TestNG中的DataProvider注解结合用于数据驱动测试。
让我们创建一个新的POJO类,确保字段名称与JSON文件中的完全相同。
1
2
3
4
5
6
7
8
9
10
11
|
@Getter
@AllArgsConstructor
public class Orders {
private String user_id;
private String product_id;
private String product_name;
private double product_amount;
private int qty;
private double tax_amt;
private double total_amt;
}
|
Lombok是一个方便的库,它使用注解(如@Getter和@AllArgsConstructor)在运行时自动生成getter和构造函数。由于需要在运行时动态初始化所有字段以生成负载,因此使用@AllArgsConstructor注解。
创建一个名为TestPostRequestWithPOJO的新Java类,并在此类中添加一个名为testCreateOrder()的测试方法来实现测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class TestPostRequestWithPOJO {
@Test
public void testCreateOrder () {
Orders orderOne = new Orders ("3", "4", "Google Pixel 9 Pro", 659.87, 1, 65.97, 725.84);
Orders[] orders = { orderOne };
given ().contentType (ContentType.JSON)
.when ()
.log ()
.all ()
.body (orders)
.post ("http://localhost:3004/addOrder")
.then ()
.log ()
.all ()
.statusCode (201)
.and ()
.assertThat ()
.body ("message", equalTo ("Orders added successfully!"));
}
}
|
使用构造函数中传递的相应订单值实例化Orders类,这将生成订单对象。接下来,创建名为Orders[]的POJO数组,它将订单作为请求体提供给测试。此Orders[]数组将允许您通过简单添加更多订单对象来添加多个订单。
1
2
3
|
Orders orderOne = new Orders ("3", "4", "Google Pixel 9 Pro", 659.87, 1, 65.97, 725.84);
Orders orderTwo = new Orders ("3", "4", "Google Pixel 10 Pro", 700.00, 1, 70.00, 770.00);
Orders[] orders = { orderOne, orderTwo };
|
提供订单数组的另一种方法是使用Java集合中的List接口。因此,实现将如下所示,使用List创建订单数组:
1
2
3
|
Orders orderOne = new Orders ("3", "4", "Google Pixel 10 Pro", 759.87, 1, 75.97, 835.84);
List<Orders> orders = new ArrayList<> ();
orders.add (orderOne);
|
这两种方法都是正确的,可以使用;这完全取决于您的选择,您觉得哪种更简单、更容易实现。
在本教程的下一部分,我将涵盖以下点以使用REST Assured测试POST API请求:
- 使用JSON文件
- 使用构建器模式和运行时DataFaker
- 响应验证
总结
测试POST API请求涉及以所需格式(JSON/XML)向服务器发送数据。可以使用原始JSON作为字符串、Java集合或POJO创建请求体,REST Assured将其序列化为JSON。REST Assured框架提供内联断言以验证状态码、响应数据和其他相关属性。
请求体是POST API请求的基本组成部分。对请求体使用动态方法很重要,因为随着项目增长,这增强了可维护性。虽然硬编码方法可以临时使用,但不建议长期使用。