接口测试 使用 rest-assured 进行接口测试

天琴圣域 for rest-assured · 2016年11月23日 · 最后由 very 回复于 2021年04月08日 · 38656 次阅读
本帖已被设为精华帖!

前言

第一次在社区发主题帖,还是挺~紧张的(雾)。
说一下发帖的原因,由于偶然机会,得知了 rest-assured 这个项目,据说很棒的样子,我就屁颠屁颠到 Github 上,先把项目 fork 过来再说,不过研究源码可能是有生之年了 (〃ω〃)。
正好我们组在使用 Java 脚本进行接口测试,会需要写一些公共方法来验证接口返回的 json 节点神马的,当然保证状态码 200 肯定是前提。之前使用的是 net.sf.json,随便贴几行代码,Object、Array、String、JSONObject 神马的互相转换取值,讲道理挺容易被绕晕的。。。

而且,给同事讲解的时候也比较尴尬(抛出一个异常的眼神你们自己体会),有时候我们为了提升效率,还是不喜欢这种绕的做法。看 rest-assured 的用户手册时,首先看的就是节点取值验证部分,然后我 o゜▽゜) o,总之非常高兴就是了。

正文

接下来我就依据文档写了一些 demo,在这里分享下自己的经验,没啥厉害的,看看热闹就行~
首先,我使用 idea 新建了一个 maven 项目,添加了以下依赖:

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>3.0.1</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>3.0.1</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>spring-mock-mvc</artifactId>
    <version>3.0.1</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>RELEASE</version>
</dependency>

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>1.8.1</version>
    <scope>provided</scope>
</dependency>

然后,写一个测试类,官方推荐我们在使用的时候,静态导入以下:

import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static io.restassured.path.json.JsonPath.from;
import static org.hamcrest.Matchers.*;
import static io.restassured.module.jsv.JsonSchemaValidator.*;

接下来就是我在接口测试中验证的常见逻辑了,实战 time,Go!

1.HTTP 状态码

@Test
public void test1() {
    Response response = get("url");//发起get请求,并获取响应
    if (response.getStatusCode() == 200) {//如果响应码等于200
     ///
    }
 }

先使用 get 方法发起请求(支持 HTTP 和 HTTPS,不需要我们手动调用不同的方法类啦),获得响应后就需要我们做进一步的处理。

2.节点值验证

比如对这样一串 json,

{
    "result": {
        "cardtablist": [
            {
                "id": 1,
                "name": "服务",
                "taburl": "",
                "type": "0"
            },
            {
                "id": 2,
                "name": "金融",
                "taburl": "https://demo/",
                "type": "1"
            }
        ]
    },
    "returncode": 0,
    "message": "ok"
}

我们可以简单写一下:

response.then().body("returncode", equalTo(0));//判断returncode是否等于
response.then().body("result.cardtablist", hasSize(2));//判断cardtablist数组的长度是否等于2
response.then().body("result.cardtablist[0].id", equalTo(1));//判断cardtablist数组第一个元素下,id字段值是否等于1
response.then().body("result.cardtablist[0].id", lessThan(2));//判断cardtablist数组第一个元素下,id字段值是否小于2
response.then().body("result.cardtablist[0].id", greaterThan(0));//判断cardtablist数组第一个元素下,id字段值是否大于0
response.then().body("result.cardtablist[0].name", not(""));//判断cardtablist第一个数组元素中name字段值不为“”
response.then().body("result.cardtablist[0].name.length()", greaterThan(10));//判断cardtablist第一个数组元素中name字段值长度大于10
List<String> dspnameStr = from(jsonStr).getList("result.adlist.findAll { it.ishavead == 1 }.dspname");//得到所有的ishavead=1的adlist数组元素,并获取其中dspname的值,放在一个集合里

3.格式化打印 json

我觉得这个功能挺赞啊,省得打开浏览器去http://json.cn/做格式化。

response.getBody().prettyPrint();//格式化打印JSON数据

当然,控制台打印的 json 字符串不带颜色,这就不要挑剔了。

4.参数化

given().param("p1", "0").param("p2", "1").get("http://server/demo");

这里把参数拿出来单独赋值,最终会拼接成形如http://server/demo?p1=0&p2=1的链接并进行访问。

5.响应时间

when().get("https://server/demo?p1=0&p2=1").then().time(lessThan(100L),TimeUnit.MILLISECONDS);//判断响应时间是否少于预期值。

6.JSON Schema Validation

这个功能我也挺喜欢的,可以通过自己编写 json 指定要验证的结构字段(比如取值范围限定、字符串整型数组类型、必要字段是否存在等),具体内容有兴趣的同学可以自学一下。此处只展示 API 的调用:

get("https://server/demo?p1=0&p2=1").then().assertThat().body(matchesJsonSchemaInClasspath("test.json"));

这里我把写好的 test.json 文件放在 idea 自动生成的 src/main/resources 路径下,里面简单写了下:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Product set",
  "type": "object",
  "properties": {
    "result": {
      "type": "object"
    },
    "returncode": {
      "type": "integer"
    },
    "message": {
      "type": "integer"
    }
  },
  "required": [
    "result",
    "returncode",
    "message"
  ]
}

这里验证点有:保证返回 result、returncode、message 字段,并对每个字段的 value 进行类型限定。
暂时写到这吧(其实是我暂时就只看了一小部分),某校长还等着吐槽我 QAQ。

心好累(:3」∠)

另外,我的打赏二维码只是开个玩笑,别当真。。。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 68 条回复 时间 点赞

终于等到这个帖子了

我也准备了一个帖子. 正打算发哪. 被你抢先了. 上次听美团的同学说, 他们在用.

思寒_seveniruby 将本帖设为了精华贴 11月23日 18:24

加精理由: rest-assured 是个优秀的接口测试框架. 期待更多的普及贴.

校长怎么吐槽你了?

很棒……
基于这一套在上层再做定制就简单很多了,像我就是苦笔一样把这一套自己做了一遍。

#6 楼 @testly 我也是. 这套东西跟我做的很像. 我在想如何结合下.

#5 楼 @026 佛曰不可说,否则某指标难保(开个玩笑 (:3」∠))

#7 楼 @seveniruby 请教一下,看这个文档类似 python 的 requests 模块,和 java 的 okhttp 模块,只看出是一个请求框架,测试框架的特性展示在什么地方?

举个 python 的例子

import requests

req = requests.get(url='www.testerhome.com/xxx')

print req.json()
#json格式

print req.status_code
#状态码

#7 楼 @seveniruby 嗯嗯.在这基础做数据驱动的模式很方便啦,目前我这边已经平台化了,每个版本接口自动化覆盖率 90%

#10 楼 @testly 为啥你们产品还这么差……

#11 楼 @Lihuazhang 这可是我无法左右咯

#12 楼 @testly 我现在想我们做测试是为了什么,不是为了保证质量,而且为了保证产品。

#13 楼 @Lihuazhang 说的有道理,责无旁贷
我们又再做新版😒 😁 😁

#14 楼 @testly ……阿里宇宙?

#15 楼 @Lihuazhang 哈哈,别黑我了,现在跟着俞永福的大文娱方向走

#9 楼 @joko 假设内容是个 json 你如何断言三层字段下的内容

#17 楼 @seveniruby
拿 python requests 作为举例


{
    "code": 200,
    "msg": "success",
    "data": {
        "user_nick": "cntao",
        "settings": {
            "nick": "t",
        },
        { "test":{
            "name":"xiaozhang"          }
        }
        { "test":"b"
        }
        "vip_level": 2,
    }
}

import requests

req = requests.get('http://testerhome.com/xx').json()
print req['code']
print req['data']['user_nick']
print req['data']['settings']['nick']
print req['data'][0]['test']
print req['data'][0]['test']['name']

输出:

  • 200
  • cntao
  • t
  • {"name":"xiaozhang"}
  • xiaozhang

貌似还是没看到适合内部服务的框架啊~路漫漫其修远兮

#18 楼 @joko 动态语言的好处是可以随便的写 query 方法而不用关心结构. 比如 req['data']['settings']['nick']. 但是这样写全结构也是挺麻烦的. 如果使用标准的 jsonpath 或者 xpath. 那么就可以写出更通用省事的写法 比如 //nick 或者..nick
另外就是在 java 目前仍然是使用最多的研发语言. 跟 jvm 保持一致是能让框架更流行通用. 让研发也能介入写接口测试.

#19 楼 @kasi 我厂也是内部服务协议,很多地方需要高度定制之后才能投入使用

弱弱问下,现在还用 jmeter 做接口测试包括自动化,是不是过时了?楼主能否指点下跟 jmeter 相比,此类框架的优点都有那些?

@testly 高度定制之后就失去框架意义了,现在在做框架各种坑,还在填坑中,尤其是跨语言

#22 楼 @hobbs jmeter 本来就不适合做接口测试. 能做但是不适合. 接口关注的是对数据的查询分析和结构判断. jmeter 还差的很远. 需要做很多的增强才行.

#24 楼 @seveniruby 嗯嗯,数据查询分析可以使用响应断言和正则匹配等来解决,结构判断确实不太方便,受教

#23 楼 @kasi 定制只局限完善支持内存通讯协议,不会干涉与业务强关联。
坑到最后只会越来越少,加油吧,跨语言这个有点棘手~

之前有段时间我也看到这块测试了,我最关心的 json schema 比对

—— 来自 TesterHome 官方 安卓客户端

感觉单纯的 json 解析满足不了需求,直接复用开发的 DAO 和 Model 更方便...

#24 楼 @seveniruby 这个框架的对返回的 json 的验证也挺好的。例如有如下的 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]
 }]
}
}

可以使用以下的验证方式:
get("/lotto").then().body("lotto.lottoId", equalTo(5));

get("/lotto").then().body("lotto.winners.winnerId", hasItems(23, 54));

理论上基层 json 应该是都可以的。我现在没有公司的电脑。我 copy 了一段 github 上的 wiki。也可以从 response 里获取 jsonpath,jsonpath 的语法也能取出字段来。

额,艾特错人了,请无视吧

#29 楼 @ycwdaaaa 哈哈, 作者巧妙的把 xml 和 jsonpath 的 query 都统一了起来了. 这点是个亮点. 我之前自己设计的框架里, xml 用 xpath, json 用 jsonpath. 相对来说 rest-assured 的设计更巧妙. 不过重新学习一套 GPath 也有点成本. 可以考虑增强他现有的 XPath 方法, 并补充上 JsonPath 的支持.

#30 楼 @seveniruby 恩,有一个不足的是验证方式仍然不够智能。例如返回的 json 很大,但是只有一个字段是随机字段。 这时候应该有一个像 assertJ 的递归验证对象一样的实现。可以选择不验证某个或某几个字段。 但现在只能一个字段一个字段的验证了。 我之前是自己写了一个责任链来达到这个目的。 再配上 assertJ-db 的数据库断言,我觉得可以满足大部分的业务场景了

微信里有个朋友说,这框架就是一个鸡肋。

#32 楼 @Lihuazhang 理由哪 嫌写起来麻烦嘛?

感觉非常好用啊,收藏~

@seveniruby 应该是要傻瓜化才适合大众~

get 方法有自己研究了一下,post 尚未研究,请问楼主研究了吗?

感觉这里提到的方法 postman 都可以满足,设计上思路感觉也差不多,有没有报告展示?参数管理或是动态参数的相关介绍?@ 843633513

赞一个

#37 楼 @liuhao121 这相当于就是一个方法的使用,报告、参数之类的,从代码层面来说如果有诉求就自行组装就好了

response.then().body("result.cardtablist[0].id", equalTo(1));这样写的话,如果返回的 json 字段名字或路径深度发生了变化,怎么做到不用大批量修改?

有没有 python 版的?

楼主介绍的 rest-assured 很适合接口输出内容固定的情况
我们公司的接口业务很多都是返回的 object 数量不定,array 元素数不定,值也不是固定的,所以只校验了 json 的格式是否正确,通过 jsonschema 实现的,当然,用 jsonschema 不仅仅可以校验格式,也可以校验某个字段的值
而且用 jsonschema 进行校验,根本不需要写测试代码,把你接口返回的内容,放到一个在线转换的网站上生成一下 jsonschema 就可以了

#42 楼 @abyssalknight 接口返回的 object 本身就不可能是一样的啊,与数据源的比对这也是接口测试必须要做的,rest-assured 适合做什么就看你怎么使用了,你自行封装一套数据源对比方法,你说的这些问题都不是问题

#43 楼 @xushizhao 老徐,买车是不是找你有优惠

#44 楼 @mads 只能优惠 4S 店信息 我记得。。我上次帮别人问过。。。

#45 楼 @xushizhao 你是内部员工还没福利啊,我们公司内购都会便宜的,你们公司不行啊

49875183 在 rest-assured 中 JsonPath 的使用 中提及了此贴 12月13日 15:11

@seveniruby 请问大神如何使用此框架生成 sig 值呐?

请问 post 请求遇到 302 重定向该如何处理

对 zz 回复

呃,302 我一般不认为是错误,不过目前没遇到过 post 的 302,一会儿我自己写个接口试试。不过考虑到劫持问题,遇到这种情况我会加个判断,状态码 302 会通过,但会打日志记录这种情况(header 等)。

对 天琴圣域 回复

嗯啊 我也再试试 一样的参数 post man 就能得到 200,代码发 post,302 我这没发成功,数据没有被修改,我一开始以为 contentType 的问题,没用,看了官网例子试了 redirect,也没用,我再试试吧 还不知道什么原因

对 zz 回复

试了一下,我用 Nginx 做了一转发,把某 post 请求 rewrite 到别的地址。用 postman 请求得到状态码是 200,用代码发是 302.
但是这种情况 302 才是正确吧。。。

对 天琴圣域 回复

恩你说的情况正确,我 Test 里写了两个请求,单发 post 现在得到 200 了(一个新增一个修改逻辑,我把新增注释掉了得到 200 了),问题没我想的那么复杂,我再排查一下,谢谢回复哈

对 zz 回复

我第二个请求用的第一个 response 返回的 cookie,但实际上返回的内容没有包含 cookie,所以注掉了能正确,现在解决了 谢谢
请问 rest-assured 有什么交流群吗

对 zz 回复

有接口测试群。。309814929

@843633513 ,对于长链接的接口,这个工具有解决方案?

对 lsy 回复

长链接是指 URL 很长?会出啥问题么。。。

对 天琴圣域 回复

服务器推技术,即时聊天方面,websocket、netty 之类,有相关指点下?

对 zhangyang 回复

结构判断也还好吧,你说 json/xml?有 XPath Assertion,还有个插件好像叫 JSONPathAssertion,当然还可以自己写插件(这算灵活?)jmeter 我觉得主要是简单易于推广,然后其实各种不灵活(合个用例累吧?单条用例调试?或者说 jmeter 上啥是用例...?可能还要定个规范,单条请求的用例,多个预置后置步骤的用例。。)。。。如果是着急搞,特别是后期又不是有代码能力来维护用例(可能你就给他们写个插件),我觉得还是可以用的,否则自己搞个不上不下的还真没 jmeter 覆盖的全

对 lsy 回复

刚工作没多久,主要就接触过 RESTful API 相关的测试,其它我也在学习哈😁

不错,这个 API 炒鸡减蛋,语法通俗易懂,值得学习

对 testly 回复

最近才看到这篇,之前是直接用的 HTTPCLIENT,哎,何必自己苦苦造轮子,这个轮子挺好用的,而且可靠性应该比我自己写的好。

尝试使用 JsonSchema 来校验返回 json,但是校验没通过,junit 用例还是显示执行成功,且校验失败也没有错误日志输出啊,怎么看是那个校验没通过呢?

在路上 在 你用过的最好用的接口自动化框架? 中提及了此贴 01月31日 12:48

maven 工程, rest-assured 使用 post 请求时提示 405 ,改用 get 请求后就 OK 了。 这个什么原因,求指导~, 不能所有接口都用 get 啊~

服务端是 post 还是 get 的?请求方式要与服务端保持一致

对 49875183 回复

是 POST,用其它工具 jmeter,postman 做 post 请求是正常的。

请教楼主:
post 的数据,如果是 json 数据,应该怎么操作呢?我在官网上看到用 map 的.但是如果是复杂的 json,嵌套好几层的那种,应该怎么处理呢?

请问 rest-assured 支持 DNS 处理吗?rest-assured 如何使用 springMockMVC 做 http 接口 mock 测试呀?

对 Boxer 回复

DNS 处理 我也想问这个问题哈

大佬,这个有断言失败时的输出设置吗?比如 n 个断言,我希望更快的定位是哪个用例场景或者值断言失败,我可以备注在代码里面,断言失败的时候输出。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册。