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

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

前言

第一次在社区发主题帖,还是挺~紧张的(雾)。
说一下发帖的原因,由于偶然机会,得知了 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 个断言,我希望更快的定位是哪个用例场景或者值断言失败,我可以备注在代码里面,断言失败的时候输出。

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