接口自动化 - 接口组合业务练习(CRUD组合)-REST-assure(Java版)

文章目录

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!

编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。



本文开始

1. 需求分析

接口自动化整体思路构建

1.1 业务需求分析

明确被测产品:petstore系统 - 宠物管理。

宠物商店接口文档:Swagger文档

宠物管理业务场景:

1.添加宠物。

2.查询宠物信息。

3.修改宠物信息。

4.删除宠物。

1.2 编写自动化脚本思路

2. 接口自动化脚本编写

  1. 首先编写CRUD单一接口,保证单一接口跑通,然后考虑业务接口组合优化,和跑通;
  2. 接口逻辑和业务逻辑可以分开

【注】

1.请求中不添加 contentType(ContentType.JSON) 会导致请求失败

2.因为HTTP协议需要明确的Content-Type标头来告诉服务器如何处理请求体。

  • asString() 和 toString() 在RestAssured中有重要区别
    1.asString(): 将HTTP响应体内容作为字符串返回
    如:asString() 返回:{"id": 1, "name": "John"}
    2.toString(): 返回Body对象的字符串表示,通常是对象本身的描述信息
    如:输出类似:io.restassured.internal.RestAssuredResponseImplBody2@1a2b3c4d

编写CRUD基础接口代码-保证每个接口测试通过

java 复制代码
/**
 * 新增-接口方法 POST
 *  url: https://petstore.swagger/pet
 */
public void add() {
	//构造请求体参数
    String newPet = "{\"id\":"+petId+",\"category\":{\"id\":0,\"name\":\"string\"},\"name\":\""+
            newPetName+"\",\"photoUrls\":[\"string\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
    given()
        .contentType(ContentType.JSON)
        .body(newPet)
        .log().all()
    .when()
        .post(baseURL)
    .then()
        .log().all();
}

/**
 * 新增方法:忽略HTTPS校验
 */
public void add2() {
    String newPet = "{\"id\":"+petId+",\"category\":{\"id\":0,\"name\":\"string\"},\"name\":\""+
            newPetName+"\",\"photoUrls\":[\"string\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
    given()
        //忽略HTTPS校验
        .relaxedHTTPSValidation()
        .contentType(ContentType.JSON)
        .body(newPet)
        .log().all()
    .when()
        .post(baseURL)
    .then()
        .log().all();
}

/**
 * 查看-接口方法 GET
 *  url: https://petstore.swagger/findByStatus?status=available
 */
public String get() {
    HashMap<String, Object> statusQuery = new HashMap<>();
    statusQuery.put("status", "available");
    String body = given()
        .queryParams(statusQuery)
        .log().all()
    .when()
        .get(baseURL + "/findByStatus")
    .then()
        .log().all()
        .extract().response()
        .getBody().asString();
    System.out.println(body);
    return body;
}

/**
 * 更新-接口方法 PUT
 *  url:  https://petstore.swagger/pet
 */
public void update() {
    String updatePet = "{\"id\":"+petId+",\"category\":{\"id\":0,\"name\":\"string\"},\"name\":\""+
            updatePetName+"\",\"photoUrls\":[\"string\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
    given()
        .contentType(ContentType.JSON)
        .body(updatePet)
        .log().all()
    .when()
        .post(baseURL)
    .then()
        .log().all();
}

/**
 * 删除-接口方法 DELETE
 *  url: https://petstore.swagger/pet/petId
 *   删除参数是在路径上,直接拼接到url上
 */
public void delete() {
    given()
        .log().all()
    .when()
        .delete(baseURL + "/" + petId)
    .then()
        .log().all();
}

测试用例业务逻辑执行:

java 复制代码
/**
 * 新增宠物测试用例
 *  执行业务逻辑:先新增,再查看验证
 */
@Order(12)
@Test
public void addTest() {
    //新增
    add();
    //查看
    String body = get();
    //校验
    DocumentContext context = JsonPath.parse(body);
    List<Long> ids = context.read("$..id");//或者使用$[*].id
    List<String> names = context.read("$..name");
    List<String> status = context.read("$..status");//$[*].status

//        System.out.println(status);
    assertAll(
        () -> assertThat(status, everyItem(equalTo("available"))),
        () -> assertThat(ids, Matchers.hasItem(Long.valueOf(petId))),
        () -> assertThat(names, Matchers.hasItem(newPetName))
    );
}

/**
 * 修改宠物测试用例
 */
@Order(13)
@Test
public void updateTest() {
    //修改宠物
    update();
    //查看修改
    String body = get();
    //断言
    DocumentContext context = JsonPath.parse(body);
    List<Long> ids = context.read("$..id");//或者使用$[*].id
    List<String> names = context.read("$..name");
    assertAll(
        //验证每一个status,都等于available
        () -> assertThat(ids, Matchers.hasItem(Long.valueOf(petId))),
        () -> assertThat(names, Matchers.hasItem(updatePetName))
    );
}

/**
 * 删除宠物测试用例
 */
@Order(14)
@Test
public void deleteTest() {
    //删除宠物
    delete();
    //查询删除结果
    String body = get();
    //断言
    DocumentContext context = JsonPath.parse(body);
    List<Long> ids = context.read("$..id");//或者使用$[*].id
    assertAll(
        //ids,都不等于petId
        () -> assertThat(ids, not(Matchers.hasItem(Long.valueOf(petId))))
    );

}

断言说明:

assertAll 是JUnit 5的特性,它允许同时执行多个断言,即使前面的断言失败,也会继续执行后面的断言,最后报告所有失败。

java 复制代码
assertAll(
      () -> assertThat(status, everyItem(equalTo("available"))),
      () -> assertThat(ids, Matchers.hasItem(Long.valueOf(petId))),
      () -> assertThat(names, Matchers.hasItem(newPetName))
);

1.检查status列表中的每个元素都等于"available"

everyItem():Hamcrest匹配器,表示"每一个元素"

equalTo("available"):匹配器,表示"等于 available"

2.检查ids列表中是否包含转换后的petId

Long.valueOf(petId):将字符串转换为Long

hasItem():Hamcrest匹配器,表示"包含某个元素"

2.3 优化

提取公共参数

java 复制代码
@BeforeAll
public static void beforeAll() {
     //公共URL提取
     baseURL = "https://petstore.swagger/pet";
     //提取需要提前设置的传递参数,这里简单构造,后续data数据参数化
     petId = "123456123456";
     newPetName = "newPet";
     updatePetName = "updatePet";
     //配置代理地址
//   RestAssured.proxy = host("127.0.0.1").withPort(8888);
 }

配置代理查看接口数据:

出现接口问题,不知道如何处理-使用代理查看接口数据

操作步骤:

1.请求前BeforeAll中:配置代理信息

java 复制代码
RestAssured.proxy = host("127.0.0.1").withPort(8888);

2.given()中忽略https校验:

java 复制代码
given().relaxedHTTPSValidation()

【注】接口发送到服务端前,拦截请求,发送到代理工具上,查看具体信息是否正确,然后再将接口发送到服务端;接口→代理工具→服务端

设置用例排序执行-Junit5配置

用例排序执行步骤:

1.test/resources目录下创建:junit-pltform.properties文件(文件名自定义)

配置如下设置:

yaml 复制代码
junit.jupiter.testmethod.order.default=org.junit.jupiter.api.MethodOrderer$OrderAnnotation

2.在测试用例中使用注释@Order()指定顺序使用即可

数字小的先执行

生成测试Allure报告

文件中导入.allure文件

通过mvn命令生成

mvn clean test -Dtest=测试类路径 allure:report

mvn allure:serve


总结

✨✨✨各位读友,本篇分享到内容是否更好的帮助你理解,如果对你有帮助给个👍赞鼓励一下吧!!
🎉🎉🎉世上没有绝望的处境,只有对处境绝望的人。
🎉🎉🎉一遇挫折就灰心丧气的人,永远是个失败者。而一向努力奋斗,坚韧不拔的人会走向成功。
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

相关推荐
鱼跃鹰飞19 小时前
设计模式系列:工厂模式
java·设计模式·系统架构
a努力。20 小时前
国家电网Java面试被问:混沌工程在分布式系统中的应用
java·开发语言·数据库·git·mysql·面试·职场和发展
Yvonne爱编码20 小时前
Java 四大内部类全解析:从设计本质到实战应用
java·开发语言·python
J2虾虾20 小时前
SpringBoot和mybatis Plus不兼容报错的问题
java·spring boot·mybatis
wypywyp20 小时前
2.虚拟机一直显示黑屏,无法打开,可能是分配的硬盘空间不够
linux·运维·服务器
毕设源码-郭学长21 小时前
【开题答辩全过程】以 基于springboot 的豪华婚车租赁系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.1 天前
Haproxy会话保持:基于Cookie优化
运维·负载均衡
Tao____1 天前
通用性物联网平台
java·物联网·mqtt·低代码·开源
曹轲恒1 天前
SpringBoot整合SpringMVC(上)
java·spring boot·spring
学习3人组1 天前
Docker 容器内文件↔本地双向复制备份
运维·docker·容器