REST-Assured,接口自动化的 "瑞士军刀"- 断言篇

本贴最后更新于 1247 天前,其中的信息可能已经时移世改

前言

在上篇文章<REST-Assured,接口自动化的 "瑞士军刀"- 初识篇> REST-Assured,接口自动化的 "瑞士军刀"- 初识篇 中有介绍了REST-Assured测试框架及基础使用,没有了解的小伙伴可以先去看看,这篇将带着大家一起来学习REST-Assured测试框架强大的断言机制。

Hamcrest与REST-Assured

Hamcrest 是一款用于编写匹配器对象的框架,可以组合创建灵活的匹配器进行断言。

官方网址:http://hamcrest.org/

可以支持Java、Python、Ruby、Objective-C 等语言

image.png

类似于TestNG单元测试框架或者Junit单元测试框架中所提供的Assert类,比如TestNG提供的断言匹配方法:

Assert.assertTrue();
Assert.assertFalse();
Assert.assertEquals();
...

先举几个在REST-Assured中用到的较多Hamcrest断言匹配方法:

//equalTo:基于传入对象的 equals 方法匹配方式,如果是数组则比较每个元素是否相等。
assertThat("lotto.lottoId", equalTo(5));
//hasItems:测试集合是否包含指定的多个元素
assertThat("lotto.winners.winnerId", hasItems(23, 54));
//...

更多的用法可以参考官方文档示例。

Hamcrest相比较上述两款单元测试框架自带的断言匹配而言更加强大、优雅、易读。所以REST-Assured官方推荐使用的断言匹配就是Hamcrest。

需要注意的是REST-Assured在使用Hamcrest的时候需要静态导入:

import static org.hamcrest.Matchers.*;

准备测试环境

我们拿官方文档中的例子来练习,Json返回数据如下:

{
"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]
 }]
}
}

为了方便我们练习,我们可以使用PostMan模拟Mock,定制我们想要的响应数据(Json/XML)

image.png

以PostMan模拟接口json响应为例,REST-Assured发起请求:

given().
when().
    get("https://013844de-a0b4-426b-b5dc-dcd3a2e5afe5.mock.pstmn.io/json").
then().
    log().all();

控制台的输出的返回响应结果:

HTTP/1.1 200 OK
Date: Fri, 16 Oct 2020 10:08:18 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: nginx
x-srv-trace: v=1;t=7889c71dfff0bf98
x-srv-span: v=1;s=9305333febed8b23
Access-Control-Allow-Origin: *
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1602842942
ETag: W/"2d1-xSYx3nsyyhHEU4lc3Wu1ZhmyStM"
Vary: Accept-Encoding
Content-Encoding: gzip

{
    "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
                ]
            }
        ]
    }
}

Json响应断言

需要注意的是REST-Assured中的json响应提取是为Groovy's GPath语法(简称GPath),而不是 Jayway's JsonPath语法。

那么GPath到底是什么?以下来自官网的说明

GPath is a path expression language integrated into Groovy which allows parts of nested structured data to be identified. In this sense, it has similar aims and scope as XPath does for XML. The two main places where you use GPath expressions is when dealing with nested POJOs or when dealing with XML

简单来说GPath是一种路径表达式语言,类似于xpath,GPath不仅可以应用于XML,还可以应用于嵌套的层级结构(比如Json、Html)。

Gpath相比较 Jayway's JsonPath语法更为简洁

比如:验证lottoId为5

given().
when().
    get("https://013844de-a0b4-426b-b5dc-dcd3a2e5afe5.mock.pstmn.io/json").
then().
    assertThat().body("json.lotto.lottoId",equalTo(5));

比如:验证winnerId为23和54

//前面部分代码跟上述一致,省略
assertThat().body("json.lotto.winners.winnerId",hasItems(23,54));

如果想要断言第一个winnerId为32,我们可以通过索引访问:

assertThat().body("json.lotto.winners.winnerId[0]",equalTo(23));

还可以通过greatThan断言大于某个值

assertThat().body("json.lotto.winners.winnerId[0]",greaterThan(20));

复杂的JsonPath解析和验证:

Xml响应断言

由于Xml响应获取指定值也是使用GPath的语法来描述的,所以和上述的语法基本一致。

我们还是拿官网的示例来练习,有如下xml文件内容:

<shopping>
      <category type="groceries">
        <item>Chocolate</item>
        <item>Coffee</item>
      </category>
      <category type="supplies">
        <item>Paper</item>
        <item quantity="4">Pens</item>
      </category>
      <category type="present">
        <item when="Aug 10">Kathryn's Birthday</item>
      </category>
</shopping>

验证第二个category节点的第一个item值为Paper

given().
when().
    get("https://013844de-a0b4-426b-b5dc-dcd3a2e5afe5.mock.pstmn.io/xml").
then().
    assertThat().body("shopping.category[1].item[0]",equalTo("Paper"));

xml还可以根据属性进行条件筛选,比如选出第一个type属性值为groceries节点的所有item文本

assertThat().body("shopping.category.find{it.@type=='groceries'}.item",hasItems("Chocolate","Coffee"));

有时候我们还可以采用简写:

assertThat().body("shopping.category.findAll{it.@type=='groceries'}",hasItems("Chocolate","Coffee"));

此表达式相比较上述的少了item,原因在于在category节点上将会自动执行toString()方法,将会获取category节点的所有子节点的文本值。

还有些时候我们在写路径的时候由于路径过长,整个表达式过于复杂,我们可以采取类似于xpath的相对路径写法,官方命名为深度优先搜索算法,其具体用法是以"**"开头,后面加上条件筛选即可。

比如:上面的例子使用深度优先搜索:

assertThat().body("**.find { it.@type == 'groceries' }",hasItems("Chocolate","Coffee"));

通过find找到符合筛选条件的第一个对应节点。

1 操作
shakebabe 在 2020-10-19 10:44:29 更新了该帖
3 回帖
请输入回帖内容 ...