JAVA自动化测试学习(接口自动化)

本文是基于小林coding的文章,主要整理学习了java接口自动化测试的一些知识,知识点主要包括:框架搭建(RestAssured、TestNG、Maven)、与 Python 对比、RestAssured vs HttpClient、数据驱动与鉴权、关联(JsonPath/Context)、Mock(WireMock)、断言(Hamcrest/AssertJ)等

1.创建可运行的最小 Maven + TestNG 项目

1.1 RestAssured+Maven+TestNG的框架相关概念

  • Maven:引入 Jar 包,管理项目结构,执行构建命令。①你不需要手动去下载项目所需要的jar包,只需要在 pom.xml 文件里写下坐标,Maven 就会自动帮你从网上下载并配置好。②定义了测试的流程(编译、测试、打包)。当你运行 mvn test 命令时,Maven 会自动触发整个测试流程。
  • jar包:其他开发者写好的很多.class代码和配置文件的“压缩包”,不用在意他是怎么实现的,我们直接导入自己的项目中就可以用。
  • pox.xml文件:是 Maven 的核心配置文件,记录了项目的基本信息(项目名称,版本号等),依赖列表(告诉maven需要用的jar包)构建配置(用哪个版本的java编译,打包时排除哪些文件)-------总的来说,他记录的是坐标,maven根据这些坐标去互联网上的“中央仓库”自动下载对应的jar包
  • RestAssured:构造请求参数,发送 HTTP 请求,解析响应结果。它是专门为 REST API (通过标准的 HTTP 动作(GET, POST, PUT, DELETE)来操作资源,数据格式以JSON 返回)设计的测试库
             given()//开始构造一个HTTP请求
                    .accept(ContentType.JSON)//表明客户端希望服务器返回的格式是JSON格式,相当于在HTTP的请求头header里加Accept: application/json
            .when()//真正的行为动作
                    .get("https://httpbin.org/get")//向指定的 URL 发送一个 GET 类型的 HTTP 请求。
            .then()//与预期结果对比并进行自动检查
                    .statusCode(200)//检查服务器返回的状态码是不是 200
                    .contentType(containsString("application/json"))//确认服务器实际返回的数据类型里确实包含了 application/json 这个字符串
                    .body("url", equalTo("https://httpbin.org/get"));//检查响应体,JSON 里的 url 字段内容得和我访问的地址一模一样
  • TestNG:负责控制测试的运行顺序、逻辑判断、数据驱动以及生成报告(1.注解:TestNG 会根据这些注解自动运行代码。2.断言:TestNG 提供的 Assert 类可以判断实际结果与预期是否相符 3.并行执行 4.数据驱动:同一段逻辑换不同的参数跑 5.测试报告,集成Allure)
@Test:最核心的注解,标记一个方法为“测试用例”。

@BeforeMethod / @AfterMethod:在每个测试方法前后执行(常用于清理缓存)。

@BeforeClass / @AfterClass:在当前类的所有测试方法前后执行一次(常用于初始化数据库连接)。

@BeforeSuite / @AfterSuite:在整套测试方案前后执行(最高层级,常用于启动服务器)。

1.2第一条真实接口测试

用 RestAssured 对外发起一次 HTTP GET 请求,并对状态码、返回类型、关键字段做断言。代码块见上文RestAssured下的代码块。

1.3完成“接口关联”的最小闭环

先调用一个接口 提取响应字段(extract/JsonPath),再把这个字段作为参数传给第二个接口,并断言回显一致。

 @Test
    public void chainedGetAndAnythingShouldMatchExtractedOrderId() {
        String orderId = given()
                .accept(ContentType.JSON)
                .queryParam("orderId", "A-10086")
                .when()
                .get("/get")
                .then()
                .statusCode(200)
                .contentType(containsString("application/json"))
                .extract()//开始提取操作
                .path("args.orderId");//从响应里提取:args.orderId

        given()
                .accept(ContentType.JSON)
                .queryParam("orderId", orderId)
                .when()
                .get("/anything")
                .then()
                .statusCode(200)
                .contentType(containsString("application/json"))
                .body("args.orderId", equalTo(orderId));
    }
//.queryParam():往网址(URL)的问号 ? 后面加东西,用来过滤、搜索或传递特定的信息给服务器。
//given().body(...)	我要发给服务器的信息。
//then().body(...)	检查服务器回馈的内容里,某项数据是否正确。

2.java接口自动化与python接口自动化对比

  • Python:语法简洁,入门较易,主流框架为Requests+Pytest+Allure,受限于GIL(尽管可以创建多线程,但任何时刻,都只有一个线程在CPU上运行)简洁高效
  • JAVA:语法严谨,是强类型语言(代码报错更早,重构更安全),主流框架为RestAssured+TestNG+Allure,它的线程是直接映射到操作系统的原生线程上的(操作系统根据 CPU 的核心数,把各个线程直接分发到不同的核心上去跑。类型安全,性能好,生态成熟

综上所述,在超大规模接口压测或者复杂数据加密计算时,首选 Java。

3.数据驱动与鉴权

3.1数据驱动(将测试脚本逻辑与数据分离)

@DataProvider:是TestNG的一个注解,把数据不断送入测试方法。其返回值必须是一个二维数组Object[][]或一个迭代器Interator<Object[]>  测试二维数组的每一行代表一次测试执行,每一列代表一个参数。

  • 代码内的二维数组,适合逻辑简单的单元测试,或参数非常固定的接口
public class LoginTest {

    // 1. 定义数据源
    @DataProvider(name = "loginData")//表示提供一批测试数据,名字叫loginData, 供@Test(dataProvider = "loginData")使用
    public Object[][] provideData() {
        return new Object[][] {
            {"user_01", "pass123", true},  // 第一轮:正常登录
            {"user_02", "error_pw", false}, // 第二轮:密码错误
            {"", "pass123", false}          // 第三轮:账号为空
        };
    }

    // 2. 引用数据源
    @Test(dataProvider = "loginData")//表示TestNG 会去找名为 loginData 的 DataProvider。然后把DataProvider 的每一行数据,依次喂给这个测试方法。
    //TestNG会执行三次testLogin,
    public void testLogin(String username, String password, boolean expectedResult) {
        System.out.println("执行测试:" + username);
        // 这里写 RestAssured 接口请求代码
        // Assert.assertEquals(actual, expectedResult);
    }
}
  • POI 读取 Excel:就是把测试的参数方法(测试用例)写到excel里,Java 通过 Apache POI 库来读取这些数据代码读出来给TestNG @DataProvider

登录接口demo实现

package com.study;//声明这个包属于com.study包

import org.testng.Assert;//断言
import org.testng.SkipException;//主动跳过测试(例如数据文件缺失时不报失败)
import org.testng.annotations.DataProvider;//定义数据源。
import org.testng.annotations.Test;//声明测试方法。

import java.io.InputStream;//读取资源文件流,这里是Excel文件

/**
 * POI + TestNG 数据驱动模板。
 * - 读取 src/test/resources/data/login_data.xlsx
 * - 表头约定:username | password | expected
 * - expected 填 true/false
 */
public class Day05ExcelDataDrivenTemplateTest {

    @DataProvider(name = "excelLoginData")//声明一个叫excelLoginData的数据提供器
    public Object[][] excelLoginData() throws Exception {
//访问修饰符--返回值类型(二维数组)--方法名--异常处理(在 Java 中,IO 操作是必须进行异常处理的)此处的操作Excel文件属于读写磁盘的IO操作
        String resourcePath = "data/login_data.xlsx";//定义资源路径
        InputStream inputStream = Thread.currentThread()//获取当前运行代码的线程
                .getContextClassLoader()//获取类加载器(ClassLoader)在 Java 中,类加载器负责寻找并加载编译后的 .class 文件和 resources 目录下的资源文件。
                .getResourceAsStream(resourcePath);//将文件的相对路径返回到一个输入流上

        if (inputStream == null) {
            throw new SkipException("跳过:未找到测试数据文件 src/test/resources/" + resourcePath);//报错跳过但可清晰定位
        }

        return ExcelDataReader.readLoginData(inputStream);
    }

    @Test(dataProvider = "excelLoginData")//表明该测试的数据源
    public void loginByExcelData(String username, String password, boolean expected) {
        // 这里先用一个本地模拟逻辑演示断言方式。
        // 接入真实接口时,把 actualResult 替换为 API 返回判断即可。
        boolean actualResult = simulateLogin(username, password);

        Assert.assertEquals(
                actualResult,
                expected,
                String.format("用户名=%s, 密码=%s 的结果与预期不一致", username, password)
        );
    }

    private boolean simulateLogin(String username, String password) {
        return !username.isBlank() && "pass123".equals(password);
    }
}

3.2鉴权

  • JWT/Token:登录后拿到的身份凭证(Token:用户成功登录后,服务端发token,目的是让服务端知道你是谁,有没有权限;JWT是Token的一种实现)
  • Bearer 头:把凭证放进请求告诉服务端“我是已登录用户”
  • BaseTest 统一注入:把这件事平台化,避免每条用例重复写,提升维护性与稳定性

HTTP 请求头里最常见的鉴权写法:Authorization: Bearer <token>

如果这个头没带、带错、或 token 过期,接口常返回 401 或 403

4.关联

4.1JsonPath(在JSON结构中快速定位和提取数据)

jsonpath是一套标准语法,使我们通过一行简单的表达式,直接定位并提取出你想要的值

4.2传递数据的容器context

context:把上个接口的产出,同步给后续所有需要它的接口。使用方法:

  • 定义容器:创建一个能被全局访问的 Map
import java.util.HashMap;
import java.util.Map;

public class TestContext {
    // 核心:用一个 Map 存储所有要传递的数据
    private static Map<String, Object> innerMap = new HashMap<>();

    // 存数据
    public static void set(String key, Object value) {
        innerMap.put(key, value);
    }

    // 取数据
    public static Object get(String key) {
        return innerMap.get(key);
    }

    // 清空(每个 Test Suite 执行完后建议清空,防止数据污染)
    public static void clear() {
        innerMap.clear();
    }
}
  • 提取并存储:在上游接口的响应断言后,利用 JsonPath 提取关键字段并 put 进容器。
@Test
public void loginTest() {
    Response response = post("/api/login", loginPayload);
    // 1. 使用 JsonPath 提取
    String token = response.jsonPath().getString("data.token");
    // 2. 存入 Context
    TestContext.set("session_token", token);
}
  • 获取并注入:在下游接口的请求发送前,从容器中 get 数据,并注入到 URL、Header 或 Body 中。
@Test
public void createOrderTest() {
    // 1. 从 Context 取出数据
    String myToken = (String) TestContext.get("session_token");

    // 2. 将数据应用到请求中
    given()
        .header("Authorization", myToken)
        .body(orderPayload)
    .when()
        .post("/api/order")
    .then()
        .statusCode(200);
}

4.3ThreadLocal

目的:为每个线程提供一份变量的副本,实现线程间的数据隔离。

public class ThreadSafeContext {
    // 关键点:使用 ThreadLocal 包裹我们的 Map
    private static ThreadLocal<Map<String, Object>> threadContext = ThreadLocal.withInitial(HashMap::new);

    // 存数据
    public static void set(String key, Object value) {
        threadContext.get().put(key, value);
    }

    // 取数据
    public static Object get(String key) {
        return threadContext.get().get(key);
    }

    // 重要:用完必须清理,否则会内存泄漏
    public static void remove() {
        threadContext.remove();
    }
}

5.Mock服务

用可控假服务去代替真实依赖,使自动化测试更稳定

  • Stub(桩):我们给 Mock 服务配置的“匹配规则 → 返回结果”。
    • 匹配规则:URL、方法、query、header、body(JSONPath/正则)。
    • 返回结果:status、headers、body、延迟、断开连接等。
  • Record/Playback(录制/回放,可选):把真实请求/响应录下来,后续直接回放(适合快速搭数据,但要注意脱敏)。
  • Contract(契约):你用 Mock 固化“接口应该长什么样”,用例就能对结构做断言,避免双方各写各的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值