JAVA自动化测试学习(接口自动化)
本文是基于小林coding的文章主要整理学习了java接口自动化测试的一些知识知识点主要包括框架搭建RestAssured、TestNG、Maven、与 Python 对比、RestAssured vs HttpClient、数据驱动与鉴权、关联JsonPath/Context、MockWireMock、断言Hamcrest/AssertJ等1.创建可运行的最小 Maven TestNG 项目1.1 RestAssuredMavenTestNG的框架相关概念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语法简洁入门较易主流框架为RequestsPytestAllure受限于GIL(尽管可以创建多线程但任何时刻都只有一个线程在CPU上运行)简洁高效JAVA:语法严谨是强类型语言代码报错更早重构更安全主流框架为RestAssuredTestNGAllure,它的线程是直接映射到操作系统的原生线程上的操作系统根据 CPU 的核心数把各个线程直接分发到不同的核心上去跑。类型安全性能好生态成熟综上所述在超大规模接口压测或者复杂数据加密计算时首选 Java。3.数据驱动与鉴权3.1数据驱动将测试脚本逻辑与数据分离DataProvider是TestNG的一个注解把数据不断送入测试方法。其返回值必须是一个二维数组Object[][]或一个迭代器InteratorObject[]测试二维数组的每一行代表一次测试执行每一列代表一个参数。代码内的二维数组适合逻辑简单的单元测试或参数非常固定的接口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库来读取这些数据代码读出来给TestNGDataProvider登录接口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或4034.关联4.1JsonPath在JSON结构中快速定位和提取数据jsonpath是一套标准语法使我们通过一行简单的表达式直接定位并提取出你想要的值4.2传递数据的容器contextcontext:把上个接口的产出同步给后续所有需要它的接口。使用方法定义容器创建一个能被全局访问的Mapimport java.util.HashMap; import java.util.Map; public class TestContext { // 核心用一个 Map 存储所有要传递的数据 private static MapString, 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 ThreadLocalMapString, 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、bodyJSONPath/正则。返回结果status、headers、body、延迟、断开连接等。Record/Playback录制/回放可选把真实请求/响应录下来后续直接回放适合快速搭数据但要注意脱敏。Contract契约你用 Mock 固化“接口应该长什么样”用例就能对结构做断言避免双方各写各的