目录
- 被测产品
- 需求说明
- 相关知识点
- 接口自动化测试实战
被测产品
PetStore 宠物商城:
- 一个在线的小型的商城。
- 主要提供了增删查改等操作接口。
- 结合 Swagger 实现了接口的管理
需求说明
- 完成宠物商城宠物管理功能接口自动化测试。
- 编写自动化测试脚本。
- 完成复杂断言。
相关知识点
形式 | 章节 | 描述 | |
---|---|---|---|
知识点 | 代理配置 | 利用代理分析测试脚本,排查请求错误 | |
知识点 | 多层嵌套响应断言 | 利用 jsonpath 进行多层嵌套的响应断言 |
实战思路
@startmindmap
scale 10
- 实战思路
** 需求分析
** 接口测试用例设计
** 编写接口自动化测试脚本
*** 脚本优化-配置代理查看接口数据
*** 脚本优化-添加日志
*** 脚本优化-使用 jsonpath 断言
** 生成测试报告
@endmindmap
需求分析
- 被测产品:宠物商店系统 - 宠物管理。
- 宠物商店接口文档:https://petstore.swagger.io/
- 宠物管理业务场景:
- 添加宠物。
- 查询宠物信息。
- 修改宠物信息。
- 删除宠物。
scale 10
autonumber
participant 测试人员 as tester
participant 宠物管理模块 as pet
participant 宠物商店 as petStore
tester → pet: 编写脚本
pet → petStore: 添加宠物
pet → petStore: 查询添加后宠物
customer → tester: 测试断言
pet → petStore: 修改宠物信息
pet → petStore: 查询添加后宠物
customer → tester: 测试断言
pet → petStore: 删除宠物
pet → petStore: 查询添加后宠物
customer → tester: 测试断言
宠物管理接口业务流程测试用例
编写自动化测试脚本思路
@startmindmap
scale 10
- 思路
** 获取接口信息
*** swagger 接口文档
*** 前端抓包
** 单步调通接口
** 根据业务流程串联起来
** 添加断言,确认流程正常
@endmindmap
脚本优化 - 配置代理查看接口数据
- 在脚本中配置代理。
- 抓包查看接口测试中的接口请求和响应数据。
// beforeAll定义一个代理的配置信息
RestAssured.proxy = host(“127.0.0.1”).withPort(8888);
given().relaxedHTTPSValidation() // 忽略HTTPS校验
执行顺序
- junit5配置文件。
#声明测试方法的排序规则
junit.jupiter.testmethod.order.default=
org.junit.jupiter.api.MethodOrderer$OrderAnnotation
生成测试报告
<!-- allure报告 -->
<allure.version>2.21.0</allure.version>
<aspectj.version>1.9.19</aspectj.version>
<allure.maven.version>2.12.0</allure.maven.version>
<allure.cmd.download.url>
https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline
</allure.cmd.download.url>
<!-- allure报告-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- allure报告-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.maven.version}</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
<allureDownloadUrl>${allure.cmd.download.url}/${allure.version}/allure-commandline-${allure.version}.zip</allureDownloadUrl>
</configuration>
</plugin>
package com.restassured.petstore;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import static io.restassured.RestAssured.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.everyItem;
import static org.junit.jupiter.api.Assertions.*;
public class PetTest {
static String baseUrl;
static String petId;
static String newPetName;
static String updatePetName;
@BeforeAll
public static void beforeAll() {
baseUrl = "https://petstore.swagger.io/v2/pet";
petId = "1234567891234567890";
newPetName = "newPet";
updatePetName = "updatePet";
RestAssured.useRelaxedHTTPSValidation();
}
//添加宠护测试用例
@Test
@Order(100)
public void addTest() {
add();
String body = query();
DocumentContext context = JsonPath.parse(body);
List<Long> ids = context.read("$..id"); //$[*]..id
System.out.println("ids:" + ids);
System.out.println("petId:" + Long.valueOf(petId));
List<String> names = context.read("$..name");//$[*]..name
System.out.println("names:" + names);
System.out.println("newPetName:" + newPetName);
List<String> status = context.read("$..status");//$[*]..status
System.out.println("status:" + status);
assertAll(
()->assertThat(status,everyItem(equalTo("avlilable"))),//匹配所有集合都有avlilable
() -> assertThat(ids, Matchers.hasItem(Long.valueOf(petId))),//匹配单个集合中有petId
() -> assertThat(names, Matchers.hasItem(newPetName))//匹配单个集合中有newPetName
);
}
//新增
//https://petstore.swagger.io/v2/pet
//jsonviewer.stack.hu
// @Test
public void add() {
String addPet = "{\"id\":" + petId + ",\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"" + newPetName + "\",\"photoUrls\":[\"newstring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.contentType(ContentType.JSON)
.body(addPet)
.when()
.post(baseUrl)
.then()
.log().all();
}
// @Test
public void add1() {
String addPet = "{\"id\":" + petId + ",\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"" + newPetName + "\",\"photoUrls\":[\"newstring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.contentType(ContentType.JSON)
.body(addPet)
.when()
.post(baseUrl)
.then()
.log().all();
}
//查看
//https://petstore.swagger.io/v2/pet/findByStatus?status=available
//https://petstore.swagger.io/v2/pet/findByStatus?status=available
// @Test
public String query() {
HashMap<String, Object> statusQuery = new HashMap<>() {{
put("status", "available");
}};
String body = given().log().all()
.queryParams(statusQuery)
.when()
.get(baseUrl + "/findByStatus")
.then()
.log().all()
.extract().response().getBody().asString();
System.out.println(body);
return body;
}
// @Test
public void query1() {
HashMap<String, Object> statusQuery = new HashMap<>() {{
put("status", "available");
}};
String body = given().log().all()
.queryParams(statusQuery)
.when()
.get(baseUrl + "/findByStatus")
.then()
.log().all()
.extract().response().getBody().asString();
System.out.println(body);
DocumentContext context = JsonPath.parse(body);
List<Long> ids = context.read("$..id");
System.out.println("ids:" + ids);
List<String> names = context.read("$..name");
System.out.println("names:" + names);
}
//更新
//https://petstore.swagger.io/v2/pet
//更新宠护测试用例
@Test
@Order(150)
public void updateTest() {
update();
String body = query();
DocumentContext context = JsonPath.parse(body);
List<Long> ids = context.read("$..id");
System.out.println("ids:" + ids);
System.out.println("petId:" + Long.valueOf(petId));
List<String> names = context.read("$..name");
System.out.println("names:" + names);
System.out.println("updatePetName:" + updatePetName);
assertAll(
() -> assertThat(ids, Matchers.hasItem(Long.valueOf(petId))),
() -> assertThat(names, Matchers.hasItem(updatePetName))
);
}
public void update() {
String updatePet = "{\"id\":" + petId + ",\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"" + updatePetName + "\",\"photoUrls\":[\"updatestring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.contentType(ContentType.JSON)
.body(updatePet)
.when()
.put(baseUrl)
.then()
.log().all();
}
// @Test
public void update1() {
String updatePet = "{\"id\":" + petId + ",\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"" + updatePetName + "\",\"photoUrls\":[\"updatestring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.contentType(ContentType.JSON)
.body(updatePet)
.when()
.put(baseUrl)
.then()
.log().all();
}
//删除
//https://petstore.swagger.io/v2/pet/Pet id
//更新宠护测试用例
@Test
@Order(200)
public void deleteTest() {
delete();
String body = query();
DocumentContext context = JsonPath.parse(body);
List<Long> ids = context.read("$..id");
System.out.println("ids:" + ids);
System.out.println("petId:" + Long.valueOf(petId));
List<String> names = context.read("$..name");
assertAll(
() -> assertThat(ids, Matchers.not(Matchers.hasItem(Long.valueOf(petId))))
);
}
public void delete() {
String body = "{\"id\":1234567890,\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"doggie\",\"photoUrls\":[\"updatestring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.when()
.delete(baseUrl + "/" + petId)
.then()
.log().all();
}
// @Test
public void delete1() {
String body = "{\"id\":1234567890,\"category\":{\"id\":0,\"name\":\"宠物狗\"},\"name\":\"doggie\",\"photoUrls\":[\"updatestring\"],\"tags\":[{\"id\":0,\"name\":\"string\"}],\"status\":\"available\"}";
given()
.when()
.delete(baseUrl + "/" + petId)
.then()
.log().all();
}
}
总结
通过 Swagger 文档获取接口信息。
使用 given-when-then 发出携带请求参数的 GET 请求。
多断言响应符合是否符合预期。
添加代理,抓包查看接口请求和响应数据。
使用 Jsonpath 提取复杂结构响应数据,然后进行断言。
生成 Allure 测试报告。
源码地址
遇到问题:
1、id设置为"1234567890",查询获取所有id代码
List ids = context.read(“$…id”);
断言 () → assertThat(ids, Matchers.hasItem(Long.valueOf(petId)))
报错:类型不匹配
解决办法:
Id写长一点就好了(1234567891234567890),我把刚才的1234567890转换成Integer类型也是ok的,类型转换为问题