Java 接口自动化入门:JUnit + RestAssured 小白实战笔记
适合刚开始学 Java 接口自动化的人:先分清 JUnit、RestAssured、Spring 的职责,再把 GET、POST、Header、Body、JSON 断言和 Bean 注入问题串起来。
1. 先分清三个东西
1.1 JUnit:负责运行测试和判断结果
JUnit 是 Java 里常用的测试框架。
它主要负责:
- 标记测试方法,比如
@Test - 运行测试用例
- 提供断言方法,比如
assertEquals、assertNotNull、assertFalse
例如:
assertEquals(200, response.getStatusCode());
意思是:
我期望状态码是 200。如果实际不是 200,这条测试就失败。
1.2 RestAssured:负责发送接口请求
RestAssured 是 Java 里常用的接口测试工具。
它主要负责:
- 发送 GET / POST / PUT / DELETE 请求
- 设置 Header
- 设置 Body
- 获取 Response
- 解析 JSON 响应
- 配合断言验证响应结果
典型写法是:
RestAssured
.given()
.when()
.get(url)
.then()
.statusCode(200);
可以理解成:
given:准备请求
when:发送请求
then:验证响应
1.3 Spring:负责管理对象和依赖注入
Spring 不是接口自动化测试必须使用的东西。
它主要负责:
- 管理 Bean
- 依赖注入
- 配置管理
- 启动 Spring 容器
所以可以先这样记:
JUnit:负责跑测试
RestAssured:负责发接口请求
Spring:负责管理对象和依赖注入
2. 接口自动化一定要用 Spring 吗?
不一定。
如果你只是从接口外部发 HTTP 请求,验证返回结果,通常可以不用 Spring。
一个轻量级接口自动化项目可以这样搭:
JUnit 5 + RestAssured + Allure + 配置文件
什么时候需要 Spring?
如果你要测试 Spring 项目内部的 Service、Repository,或者想复用项目里的 Bean,就可能需要 Spring 测试上下文。
例如:
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testUser() {
userService.getUser();
}
}
这里 @SpringBootTest 的作用是启动 Spring 测试上下文,让 Spring 帮你创建 Bean、注入 Bean。
以前 Bean 注入失败,很可能是因为:
你以为自己在 Spring 环境里测试,
但实际只是普通 JUnit 测试。
JUnit 本身不负责 Bean 注入。
Spring 容器才负责 Bean 注入。
3. 先准备依赖
如果是 Maven 项目,可以先加入 JUnit 5、RestAssured 和 Jackson。
为了公众号里更容易看清楚,先把依赖拆成表格:
| 用途 | groupId | artifactId | version | scope |
|---|---|---|---|---|
| JUnit 5 测试框架 | org.junit.jupiter | junit-jupiter | 5.10.2 | test |
| RestAssured 接口测试 | io.rest-assured | rest-assured | 5.4.0 | test |
| JSON 序列化支持 | com.fasterxml.jackson.core | jackson-databind | 2.17.1 | test |
复制到 pom.xml 里时,可以放在 <dependencies> 下面:
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
<scope>test</scope>
</dependency>
</dependencies>
补充说明:
RestAssured 可以把
Map或对象序列化成 JSON,但通常需要项目里有 Jackson、Gson 这类 JSON mapper。简单项目里加上jackson-databind最省心。
4. 普通 JUnit 测试怎么写?
如果只是测试普通 Java 方法,不需要 Spring,也不需要 RestAssured。
比如有一个类:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
测试可以这样写:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(1, 2);
assertEquals(3, result);
}
}
这个结构就是:
准备对象 → 调用方法 → 断言结果
也就是常说的:
Arrange → Act → Assert
5. RestAssured 的 GET 请求怎么写?
比如健康检查接口:
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HealthCheckTest {
@Test
public void testHealthCheck() {
Response response = RestAssured.given()
.relaxedHTTPSValidation()
.accept("application/json")
.when()
.get("https://localhost:8443/fineract-provider/actuator/health");
assertEquals(200, response.getStatusCode());
String status = response.jsonPath().getString("status");
assertEquals("UP", status);
}
}
这段代码的意思是:
发送 GET 请求到健康检查接口;
断言 HTTP 状态码是 200;
再断言响应 JSON 里的 status 字段是 UP。
其中:
.relaxedHTTPSValidation()
意思是放宽 HTTPS 证书校验。
本地开发环境经常使用自签名证书,如果不放宽校验,可能会出现 SSL 相关错误。
但注意:
本地测试环境可以用 relaxedHTTPSValidation;
生产环境一般不建议随便跳过证书校验。
6. response.jsonPath().getString(“status”) 是什么意思?
这句:
String status = response.jsonPath().getString("status");
可以拆成三部分:
response:
接口返回的完整响应。
jsonPath():
把响应体当成 JSON 来解析。
getString("status"):
取出 JSON 里的 status 字段,并转成 String。
如果接口返回:
{
"status": "UP"
}
那么:
response.jsonPath().getString("status")
拿到的就是:
UP
如果 JSON 是嵌套的:
{
"user": {
"name": "Lea",
"age": 18
}
}
可以这样取:
String name = response.jsonPath().getString("user.name");
int age = response.jsonPath().getInt("user.age");
如果 JSON 里有数组:
{
"users": [
{
"id": 1,
"name": "Lea"
},
{
"id": 2,
"name": "Tom"
}
]
}
可以这样取:
String firstName = response.jsonPath().getString("users[0].name");
int secondId = response.jsonPath().getInt("users[1].id");
数组下标从 0 开始。
7. RestAssured 的 POST 请求怎么写?
POST 通常会带请求体。
比如登录接口要传:
{
"username": "mifos",
"password": "password"
}
可以用字符串写:
String requestBody = """
{
"username": "mifos",
"password": "password"
}
""";
Response response = RestAssured.given()
.relaxedHTTPSValidation()
.contentType("application/json")
.accept("application/json")
.body(requestBody)
.when()
.post("https://localhost:8443/fineract-provider/api/v1/authentication");
核心是:
.contentType("application/json")
.body(requestBody)
.post(url)
意思是:
我要发送 JSON 请求体;
请求体内容是 requestBody;
请求方式是 POST。
补充一下:
Content-Type:告诉服务端,我发过去的请求体是什么格式。
Accept:告诉服务端,我希望拿到什么格式的响应。
8. POST 请求的 Body 可以放 Map 吗?
可以。
简单 JSON 很适合用 Map。
import java.util.HashMap;
import java.util.Map;
Map<String, Object> body = new HashMap<>();
body.put("username", "mifos");
body.put("password", "password");
Response response = RestAssured.given()
.relaxedHTTPSValidation()
.contentType("application/json")
.accept("application/json")
.body(body)
.when()
.post("https://localhost:8443/fineract-provider/api/v1/authentication");
这里:
.body(body)
RestAssured 会把 Map 作为请求体发送。
如果指定:
.contentType("application/json")
通常就会按 JSON 方式序列化并发出去。
对应 JSON 大概是:
{
"username": "mifos",
"password": "password"
}
如果是嵌套 JSON,也可以 Map 套 Map。
不过实际项目里,如果请求体很复杂,更推荐:
DTO 实体类
或者读取 JSON 文件
这样比在测试代码里手写一大坨 Map 更清楚。
9. 怎么断言 base64EncodedAuthenticationKey 不为空?
以 Fineract 登录接口为例,响应里可能有:
{
"base64EncodedAuthenticationKey": "xxxxxx"
}
可以先取出来:
String base64Key = response.jsonPath().getString("base64EncodedAuthenticationKey");
然后断言:
assertNotNull(base64Key);
assertFalse(base64Key.trim().isEmpty());
这里比只写 assertNotNull 更严谨。
因为:
assertNotNull 只能判断不是 null;
但是空字符串 "" 也不是 null。
所以更稳的判断是:
不能为 null;
去掉空格后也不能为空字符串。
需要导入:
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertFalse;
10. GET 请求怎么加 Authorization Header?
以 Fineract 为例,如果接口要求:
Header:
Authorization = Basic {base64EncodedAuthenticationKey}
RestAssured 可以这样写:
Response response = RestAssured.given()
.relaxedHTTPSValidation()
.header("Authorization", "Basic " + base64EncodedAuthenticationKey)
.when()
.get("https://localhost:8443/fineract-provider/api/v1/clients");
注意:
"Basic " + base64EncodedAuthenticationKey
Basic 后面有一个空格。
如果接口还要求租户 Header,比如 Fineract 常见的 tenant header,可以加:
.header("Fineract-Platform-TenantId", "default")
完整示例:
Response response = RestAssured.given()
.relaxedHTTPSValidation()
.header("Authorization", "Basic " + base64EncodedAuthenticationKey)
.header("Fineract-Platform-TenantId", "default")
.when()
.get("https://localhost:8443/fineract-provider/api/v1/clients");
assertEquals(200, response.getStatusCode());
补充一个容易混的点:
标准 Basic Auth 通常是
base64(username:password)。这里使用base64EncodedAuthenticationKey是 Fineract 这类接口返回后的用法,具体项目要以接口文档为准。
11. 登录后再调用接口的完整示例
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class FineractApiTest {
@Test
public void testLoginAndGetClients() {
Map<String, Object> loginBody = new HashMap<>();
loginBody.put("username", "mifos");
loginBody.put("password", "password");
Response loginResponse = RestAssured.given()
.relaxedHTTPSValidation()
.contentType("application/json")
.accept("application/json")
.body(loginBody)
.when()
.post("https://localhost:8443/fineract-provider/api/v1/authentication");
assertEquals(200, loginResponse.getStatusCode());
String base64EncodedAuthenticationKey =
loginResponse.jsonPath().getString("base64EncodedAuthenticationKey");
assertNotNull(base64EncodedAuthenticationKey);
assertFalse(base64EncodedAuthenticationKey.trim().isEmpty());
Response clientsResponse = RestAssured.given()
.relaxedHTTPSValidation()
.header("Authorization", "Basic " + base64EncodedAuthenticationKey)
.header("Fineract-Platform-TenantId", "default")
.accept("application/json")
.when()
.get("https://localhost:8443/fineract-provider/api/v1/clients");
assertEquals(200, clientsResponse.getStatusCode());
}
}
这段代码的流程是:
1. 调登录接口
2. 从登录响应里取 base64EncodedAuthenticationKey
3. 判断 key 不为空
4. 把 key 拼到 Authorization Header 里
5. 再调需要认证的 GET 接口
6. 断言状态码是 200
12. Java 访问修饰符:private、protected、同包
Java 里 private、protected、public 是访问修饰符。
它们控制:
这个属性或方法,能被谁访问?
常见规则:
| 修饰符 | 本类 | 同包 | 子类 | 其他包非子类 |
|---|---|---|---|---|
| private | 可以 | 不可以 | 不可以 | 不可以 |
| 默认不写 | 可以 | 可以 | 不可以 | 不可以 |
| protected | 可以 | 可以 | 可以 | 不可以 |
| public | 可以 | 可以 | 可以 | 可以 |
严谨一点说:
protected在跨包子类场景下有一些访问细节限制。入门阶段先记成“本类、同包、子类可访问”即可,实际写代码时再结合具体继承关系判断。
13. 什么叫同一个包?
看 Java 文件第一行:
package com.lea.demo;
如果两个类的 package 完全一样,就是同一个包。
比如:
package com.lea.demo;
public class User {
}
和:
package com.lea.demo;
public class UserService {
}
它们都是:
package com.lea.demo;
所以是同包。
注意:
package com.lea.demo;
和:
package com.lea.demo.user;
不是同一个包。
com.lea.demo.user 是子包,但 Java 不认为它和 com.lea.demo 是同包。
14. private 怎么理解?
private String name;
意思是:
这个字段只有当前类自己能访问。
外部类不能直接访问。
通常用 private + getter/setter:
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这样做叫封装。
核心目的:
不让外部随便改内部数据;
而是通过方法提供一个可控入口。
15. protected 怎么理解?
protected String baseUrl;
意思是:
本类可以用;
同包可以用;
子类可以用。
在测试框架里,protected 经常出现在 BaseTest 里。
比如:
public class BaseApiTest {
protected String baseUrl = "https://localhost:8443";
protected String getToken() {
return "token";
}
}
子类测试类可以继承使用:
import org.junit.jupiter.api.Test;
public class ClientApiTest extends BaseApiTest {
@Test
public void testClient() {
System.out.println(baseUrl);
System.out.println(getToken());
}
}
这种场景用 protected 比较合理:
这些能力不想完全 public;
但希望子类测试类可以复用。
16. 最后串成一条线
今天最重要的点:
- JUnit 是测试框架,负责运行测试和断言。
- RestAssured 是接口测试工具,负责发 HTTP 请求和解析响应。
- Spring 不是接口自动化必须的,只有需要 Bean 注入或复用 Spring 容器时才需要。
- 普通 Java 单元测试直接
new对象即可。 - 如果要
@Autowired,测试类通常需要跑在 Spring 测试环境里。 - GET 请求用
.get(url)。 - POST 请求用
.post(url),请求体放.body(...)。 - JSON 请求体建议写
.contentType("application/json")。 - Header 用
.header("key", "value")。 - Basic Authorization 写法是:
.header("Authorization", "Basic " + base64EncodedAuthenticationKey)
- JSON 字段提取写法是:
response.jsonPath().getString("字段名")
- 不为空断言推荐写:
assertNotNull(value);
assertFalse(value.trim().isEmpty());
最核心的一句话:
接口自动化测试 = 发请求 → 拿响应 → 提取字段 → 做断言 → 生成报告
把 JUnit、RestAssured、Spring Bean 注入、Header、Body、JSON 断言这几个点串起来之后,接口自动化就不再是一堆零散 API,而是一条清楚的测试流程。
更多推荐


所有评论(0)