在上一篇文章中,我们初步探讨了 REST Assured 的应用实践,还有很多丰富的用法需要慢慢探索研究。而 REST Assured 提供的完整断言手段,是测试工程师最常用最重要的功能之一。断言该如何使用呢?
这里以 rest-assured 官方给的一个示例做演示学习
{
"lotto":{
"lottoId":5,
"winning-numbers":[2,45,34,23,7,5,3],
"winners":[{
"winnerId":23,
"numbers":[2,45,34,23,3,5]
},{
"winnerId":54,
"numbers":[52,3,12,11,18,22]
}]
}
}
复制代码
在本地使用 python -m CGIHTTPServer 临时搭建起一个服务:
根节点.子节点 1)我们可以使用根节点.(点)子节点的方式一层层的找下去,例如我们需要对 lottoId 等于 5 进行断言:
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all().body("lotto.lottoId",equalTo(5));
}
复制代码
2)如果我们想要断言 winners 数组下面的 winnerId,检查 23 和 54 是否包含其中,可以如下 lotto.winners.winnerId 写法
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all()
.body("lotto.winners.winnerId",hasItems(54,23));
}
复制代码
索引取值
1)如果我们想要取某些相同字段中的某一个,可以使用类似索引的方式获取,例如想要断言 winners 数组下面的 winnerId 的第一个值是否为 23,可以使用 lotto.winners.winnerId[0],写法如下:
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all()
.body("lotto.winners.winnerId[0]",equalTo(23));
}
复制代码
2)如果我们想要取某些相同字段中的最后一个,可以使用 -1 作为索引,例如断言断言 winners 数组下面的 winnerId 的最后一个的值是否为 54
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all()
.body("lotto.winners.winnerId[-1]",equalTo(54));
}
复制代码
findAll 有时候我们需要获取符合某些条件的结果来进行断言,这里 findAll 可以帮助我们实现,我们可以在 findAll 方法中写筛选条件,例如我们想取 winnerId 的值在大于或等于 30 小于 60 之间的结果进行断言,具体写法如下:
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all()
.body("lotto.winners.findAll{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId[0]",equalTo(54));
}
复制代码
find find 的用法与 findAll 基本一致,只是 find 默认取匹配到的第一个:
@Test
void testGPath(){
given().
when().
log().all().get("http://127.0.0.1:8000/restAssured.json").
then().
log().all()
.body("lotto.winners.find{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId",equalTo(54));
}
复制代码
将上述各个断言语法写在一起,实际运行校验结果:
上面介绍了,GPath 也支持 XML 格式的断言,这里再以 rest-assured 官方给的一个实例做演示
<shopping>
<category type="groceries">
<item>
<name>Chocolate</name>
<price>10</price>
</item>
<item>
<name>Coffee</name>
<price>20</price>
</item>
</category>
<category type="supplies">
<item>
<name>Paper</name>
<price>5</price>
</item>
<item quantity="4">
<name>Pens</name>
<price>15</price>
</item>
</category>
<category type="present">
<item when="Aug 10">
<name>Kathryn's Birthday</name>
<price>200</price>
</item>
</category>
</shopping>
复制代码
再次在本地搭起一个临时服务:
若我们要对第二个 name 的值 Coffee 进行断言,写法如下:
@Test
void testXML(){
when().
get("http://127.0.0.1:8000/restAssured.xml").
then().
log().all().
body("shopping.category[0].item[1].name",equalTo("Coffee"));
}
复制代码
size() 可以利用 size() 方法来获取对应节点的数量,例如这里要断言 category 的数量:
@Test
void testXML(){
when().
get("http://127.0.0.1:8000/restAssured.xml").
then().
log().all()
.body("shopping.category.size()",equalTo(3));
}
复制代码
it.@type、it.price 在 xml 中 断言中,可以利用 it. 属性或节点的值来作为筛选条件; 例如这里要获取 type 为 supplies 的 category 下的第一个 item 的 name,以及获取 price 为 10 的商品名 name。
@Test
void testXML(){
when().
get("http://127.0.0.1:8000/restAssured.xml").
then().
log().all()
.body("shopping.category.findAll{ it.@type == 'supplies' }.item[0].name",equalTo("Paper"))
.body("shopping.category.item.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
}
复制代码
.findAll 对于 xml 中有一个特别的语法,.findAll,可以直接忽略前面的节点,直接对筛选条件进行匹配,依然获取 price 为 10 的商品名 name,写法如下:
@Test
void testXML(){
when().
get("http://127.0.0.1:8000/restAssured.xml").
then().
log().all()
.body("**.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
}
复制代码
将上述各个断言语法写在一起,实际运行校验结果:
在实际工作中,对接口返回值进行断言校验,除了常用字段的断言检测以外,还要对其他字段的类型进行检测,原因在于:
对返回的字段一个个写断言显然是非常耗时的,这个时候就需要一个模板,可以定义好数据类型和匹配条件,除了关键参数外,其余可直接通过此模板来断言,这个就要请出 JsonSchema 了
先对上述的 json 例子做少许修改,增加一个 String 类型的 winnername 字段,这里可以先你不用疑惑为什么加,后续自有其演示作用
1)首先要借助于 Json schema tool 的网站https://www.jsonschema.net/,将返回 json 字符串复制到页面左边,然后点击 INFER SHCEMA,就会自动转换为 schema json 文件类型,会将每个地段的返回值类型都设置一个默认类型; 在 pattern 中也可以写正则进行匹配
2)点击“设置”按钮会出现各个类型返回值更详细的断言设置,这个就是 schema 最常用也是最实用的功能,也可以对每种类型的字段最更细化的区间值校验或者断言,例如长度,取值范围等,具体感兴趣的话可以从官网学习深入学习;平常对重要字段的校验我通常会选用其他断言,比如 hamcrest 断言
3)选择复制功能,可以将生成的 schema 模板保存下来
4)添加 maven 依赖,在 rest-assured 完成支持
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>4.0.0</version>
</dependency>
复制代码
5)使用 matchesJsonSchemaInClasspath 方法对响应结果进行 schema 断言
@Test
void jsonSchemaTest(){
get("http://127.0.0.1:8000/restAssured.json").
then().log().all()
.body(matchesJsonSchemaInClasspath("jsonSchema.json"));
}
复制代码
运行结果:
运行查看断言结果:
很明显用例执行失败,当我们定义了 winnername 为 String 类型后,返回 null 就会断言失败,这显然不符合我们的需求,会造成用例执行结果的误判,这个时候我们需要使 winnername 即可以为 String 类型,又可以为 null;
这就要用到 jsonSchema 提供的 Combining schemas 方法了 Combining schemas 提供了如下几种方式:
这里我们选取 anyOf(任何一项满足即可)来完成上述的举例,将原来的 type 换成 String 和 null 任何一个都支持的类型:
再次运行用例,查看断言结果:
用例完美通过,到此结束~
另外,在我们实际工作中,很多时候并不是直接对响应结果直接断言,我们可能需要获取响应结果中的某些值,将这些值传递到下一个接口或者和其他接口的响应进行比较断言,这就涉及到了对响应 response 的获取与处理了,后续文章继续探讨。
更多学习资料戳!!!
https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=infoQ×tamp=1662366626&author=xueqi
评论