一、什么是rest-assured
现在,越来越多的 Web 应用转向了RESTful的架构,很多产品和应用暴露给用户的往往就是一组 REST API,这 样有一个好处,用户可以根据需要,调用不同的 API,整合出自己的应用出来。从这个角度来讲,Web 开发的成本会越来越低,人们不必再维护自己的信息孤岛,而是使用 REST API 这种组合模式。
![](https://img-blog.csdnimg.cn/img_convert/27ccf59631f43773d15db9d1e5001cbd.png)
那么,作为 REST API 的提供者,如何确保 API 的稳定性与正确性呢?全面系统的测试是必不可少的。Java 程 序员常常借助于 JUnit 来测试自己的 REST API,不,应该这样说,Java 程序员常常借助于JUnit 来测试 REST API的实现!从某种角度来说,这是一种“白盒测试”,Java 程序员清楚地知道正在测试的是哪个类、哪个方 法,而不是从用户的角度出发,测试的是哪个REST API。
![](https://img-blog.csdnimg.cn/img_convert/d8e428af47542aeb704d0a0c435087a1.png)
Rest-Assured 是一套由 Java 实现的 REST API测试框架,它是一个轻量级的REST API 客户端,可以直接编写代码向服务器端发起 HTTP请求,并验证返回结果;它的语法非常简洁,是一种专为测试 REST API 而设计的 DSL。使用 Rest-Assured 测试 REST API,就和真正的用户使用 REST API 一样,只不过 Rest-Assured 让这一切变得自动化了。
![](https://img-blog.csdnimg.cn/img_convert/0af60b7f1ce448acb563f5be77111b6d.png)
二、模拟get请求
雪球网是一个股票投资网站,你可以使用网站的搜索功能来查询股票信息,比如我们想查询sougou的信息,下 面利用了charles分析工具来查看请求和回答:
这是一个Get请求,返回的内容格式如下:
![](https://img-blog.csdnimg.cn/img_convert/7fe5b5ba9c7ae8f9cfca2e122700f664.png)
现在,我们使用 Rest-Assured 来编写一个简单的测试程序调用相同的Get请求:
- 第一步,我们要判断这是什么格式数据:json
- 第二步,确定请求地址:从charles的结果中获取y为https://xueqiu.com/stock/search.json
- 第三步,填写表单:从chrome浏览器检查结果中查询request的query信息是code:sougou
我们的代码也很简单:
![](https://img-blog.csdnimg.cn/img_convert/1d6e3a35c8fd6304aa2f5f55422b3a10.png)
返回的结果却很残酷:
![](https://img-blog.csdnimg.cn/img_convert/bb8021a0d0beec02050e6428750f91a8.png)
与登陆账号,刷新页面有关的话,我首先想到了cookie,网站都用cookie来保存账号相关信息,于是加入 cookie:
![](https://img-blog.csdnimg.cn/img_convert/c201ad400a44118b19af49e28d2ac9cc.png)
返回结果正确,你问我惊不惊喜,老实回答,不惊喜。因为我搞不明白为什么一个查询需要cookie验证,如果 不加cookie,返回的信息却是没有登陆!
![](https://img-blog.csdnimg.cn/img_convert/eeb763c3c345e23e97a1d0f8af1e6222.png)
显然,我的cookie并不包含登陆信息,因为我压根就没有登陆,当然这是网站的设计,与rest-assured无关。
![](https://img-blog.csdnimg.cn/img_convert/86cab13e25ab1f1175bd07c8959b7255.png)
更进一步
怎么区别xml与json
答:你看就知道了嘛,xml长这个样子
![](https://img-blog.csdnimg.cn/img_convert/afb381c8115290ac7576f5a6126d89a5.png)
json长这个样子
![](https://img-blog.csdnimg.cn/img_convert/32947067ae86b79a001b885046955355.png)
given,when,then分别是什么
![](https://img-blog.csdnimg.cn/img_convert/0c7afa67808774ab5fc2cac190ff3d0a.png)
答:given用于放置需要的参数,比如上面例子中,我将访问参数:code和cookie放到了given里;when用于填 写要访问的url;then进行断言,来来判断结果是否正确。
三、模拟post请求
有的时候,我们想提交表单,这种情况下使用get会非常被动,于是post登场了。
![](https://img-blog.csdnimg.cn/img_convert/188a81a08d0ff29a7bcf41209e297a91.png)
下面是代码。
![](https://img-blog.csdnimg.cn/img_convert/0e2597a74c853c325f7bd49d51697132.png)
我相信此时你的内心是这样的。
![](https://img-blog.csdnimg.cn/img_convert/31848ec92b1916d93181bc1297e9487a.png)
别着急,下面我会讲清楚…
在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是 如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,非常紧急的警车可能被前面的汽车拦堵在路上,整个交通系统一定会瘫痪。
![](https://img-blog.csdnimg.cn/img_convert/dc3d2ed4c1d26bd0eb8568c7144d29b4.png)
为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(设置method为GET),而且要求 把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放 在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。
![](https://img-blog.csdnimg.cn/img_convert/b553c8af3626a34841e2460e809b11fc.png)
四、使用断言
使用equalTo
在前面,我们使用了equalTo判断值是否是“搜狗”:
![](https://img-blog.csdnimg.cn/img_convert/7b90e8383b7effa92d682b7823022125.png)
它的作用显而易见:判断值是否相同。比如下面的例子
![](https://img-blog.csdnimg.cn/img_convert/b3fc0d8baf4e98d6580e761a1cf21066.png)
如果你想验证lottoId是否等于5,你可以这样做:
![](https://img-blog.csdnimg.cn/img_convert/bfc3356f822a14df6ab8c445e504dd29.png)
使用hasItems
![](https://img-blog.csdnimg.cn/img_convert/d607cfa573440a9b23f7f9840a7dfc6e.png)
![](https://img-blog.csdnimg.cn/img_convert/bc4b1df5666f293d3845eff9bf3c5930.png)
你可以用再次equalTo(),对winnerId[0]用一次,对winnerId[1]用一次。
![](https://img-blog.csdnimg.cn/img_convert/0518c70814f6c6dd1ed267700898d339.png)
哈哈,当然不是。你可以使用hasItems,它是这么使用的:
![](https://img-blog.csdnimg.cn/img_convert/c16430c8f8d0808b0b6949f78ca71780.png)
从根开始定位
![](https://img-blog.csdnimg.cn/img_convert/c96b847fffc954a698e6314bce788cf8.png)
![](https://img-blog.csdnimg.cn/img_convert/39624451c82053ed66ef0dfb8ceb5108.png)
额…请教王师傅。
![](https://img-blog.csdnimg.cn/img_convert/610c9fb325fdd39d488c3c312d58c040.png)
比如下面的代码,我们可以这么验证:
![](https://img-blog.csdnimg.cn/img_convert/e430d2b4b25dbb8414a268a8f774ba92.png)
使用find
![](https://img-blog.csdnimg.cn/img_convert/a43d2b0c54837ea7ef04a17aba4846bc.png)
![](https://img-blog.csdnimg.cn/img_convert/9c238d1ecee39639f09e1ec3c7329a43.png)
![](https://img-blog.csdnimg.cn/img_convert/1f74d8fc4395e103ed7e91d420421320.png)
答对了,请一定要记住xml和json的区别,不要混谈,那么你能编写一个测试来验证杂货(groceries)的类别是 否包含巧克力(Chocolate)和咖啡(Coffe)吗?
![](https://img-blog.csdnimg.cn/img_convert/0eda9f5305a05537e64445e83371b8b2.png)
![](https://img-blog.csdnimg.cn/img_convert/ed87423ebe96d71388d1345a05ccc617.png)
这确实达到了我的要求,但代码明显有很多bug,如果我更改了category的位置,像下面这样,你的代码就不 适用了,我不难为你了,请王师傅来解答吧:
![](https://img-blog.csdnimg.cn/img_convert/3d3ca5dfdadaaf820ea33006d1ccaf7e.png)
![](https://img-blog.csdnimg.cn/img_convert/df3cdd9eab93a839eac47ca9e0194883.png)
![](https://img-blog.csdnimg.cn/img_convert/383044713b6b0aa4931e72e2c465a280.png)
find的用法展示的很清楚,不需要我多讲,当然还有一点要注意,你可以这么使用find:
![](https://img-blog.csdnimg.cn/img_convert/f34a71b3882015f5e3a53e6603c61b9d.png)
**是个特殊用法,它从xml文档根部开始,进行深度搜索,直到找到符合我们需要的项。
![](https://img-blog.csdnimg.cn/img_convert/fd948e1675bf7dafe42faa979a274c29.png)
使用findAll
![](https://img-blog.csdnimg.cn/img_convert/702011d3d2f5405e1fe81a3d9a1ca096.png)
现在我手头只有20块钱,我只能买两本书,我更喜欢世纪的谚语和白鲸记,现在的任务是:挑选出格低于10的书籍,并且标题是“世纪的谚语(Sayings of the Century)”和“白鲸记(Moby Dick)”
![](https://img-blog.csdnimg.cn/img_convert/06453e1c0a0c5f671c01793b32d79249.png)
![](https://img-blog.csdnimg.cn/img_convert/e0f080b15e4ceb705278c6b076dcc77e.png)
对的,这时候应该使用findAll,可以粗鲁的认为多个find的叠加。findAll可以筛选出一批符合要求的数据,而 find只能筛选出一个符合要求的数据,这就像是我们只能挑出一个人领取一等奖,但有很多人可以拿参与奖, 两个方法都有自己的用武之地。
![](https://img-blog.csdnimg.cn/img_convert/f39f25be3b047f0c316aa1556f7dae58.png)
下面的代码展示了findAll的用法:
![](https://img-blog.csdnimg.cn/img_convert/a79143eab330ca76d3d71b76460ec5a9.png)
五、提取想要的值
有时候,我们并不想验证是否正确,我们只想取出这个值以进行下一步处理,比如我想取出next的链接:/title?page=2,这种情况怎么办呢?
![](https://img-blog.csdnimg.cn/img_convert/f0af32e8c43994ab9f920d81f5cffec6.png)
下面的代码判断内容是不是JSON,并且标题是My Title的话,就返回href链接/title?page=2,这个值被存放在nextTitleLink中,以供我们以后使用。
![](https://img-blog.csdnimg.cn/img_convert/d174ad50ece5cf58f378ccebc45ad53a.png)
![](https://img-blog.csdnimg.cn/img_convert/852c01cef19624cd8bc3961075fa7390.png)
当然,有两点需要注意:
- 返回类型是Response,我们可以用Response.xxx来二次提取想要的值。
- extract().后面是response()方法,不要写错了。
六、更改默认值
rest-assured有很多默认值,也正因为如此,需要我们的填的参数可以很少,也可以很多,就像画画一样,可以很精致,也可以很简洁。
![](https://img-blog.csdnimg.cn/img_convert/7e23f7eae8de38d93110519e5459eba6.png)
修改端口
rest-assured发起请求时,默认使用的host为localhost,端口为8080,如果你想使用不同的端口,你可以这样做:
![](https://img-blog.csdnimg.cn/img_convert/0e3f8046df02f78615b71e26b72ce791.png)
或者是这样
![](https://img-blog.csdnimg.cn/img_convert/16d4edfa3a17fbf3eec6b000135a969f.png)
或者
![](https://img-blog.csdnimg.cn/img_convert/34c59180da36aeb043bcb8788ba58e3f.png)
修改baseURI和basePath
你也可能改变默认的baseURI、basePath
![](https://img-blog.csdnimg.cn/img_convert/1cdd5843599b30ec253a3bd8d822e7fd.png)
这就意味着,类似 get("/hello") 这样的一个请求,其实完整的请求为:http://myhost.com:80/resource/hello , 并且使用基础授权认证"username" and “password”。
其他
其他的默认值可以参考下面:
![](https://img-blog.csdnimg.cn/img_convert/7379014072f32cdcac30b9a80d43a47f.png)
重置
你也可以重置为标准的baseURL(localhost)、basePath(空)、标准端口port(8080)、标准根路径root path(" "),默 认的认证scheme(none)以及URL编码(true),通过下面的方法重置:
![](https://img-blog.csdnimg.cn/img_convert/ca003739cbe856befe6c626af7d42955.png)
七、specification
在不同的测试用例当中,我们可能会有重复的响应断言或者是请求参数,那么我们可以将重复的这一部分提取出来定义一个规范或者模板,这样的话在后续的测试用例当中就可以使用这个规范模板了。
![](https://img-blog.csdnimg.cn/img_convert/722d34446877917c15594f9f9ed04688.png)
为了达到这个效果,我们可以使用RequestSpecBuilder或 ResponseSpecBuilder来实现,它们之间的区别 是,前者用在请求中,后者则用在body中。
ResponseSpecification重用
例如,你想在多个测试用例中,都使用这样的断言:判断响应状态码是否为200,并且Json数组"x.y"的大小是否 等于2。你可以定义一个ResponseSpecBuilder来实现这个功能:
![](https://img-blog.csdnimg.cn/img_convert/3c0bb12497d0edda1491cac81d1a88f1.png)
在这个例子中,需要重用的两个断言数据被定义在"responseSpec",并且与另外一个body断言合并,组成了这 个测试用例中全部的断言,那么这个测试用例需要全部断言都通过用例结果才会通过,一旦其中一个断言失 败,则测试用例的测试结果为失败。
RequestSpecification重用
同样,假如你想在多个测试用例中重用请求数据,可以通过下面的代码来实现:
![](https://img-blog.csdnimg.cn/img_convert/6fd1b68e1c4da5b412f2a3288dfad5db.png)
这里的请求数据被合并在"requestSpec"中,所以这个请求包含了两个参数(“parameter1"和"parameter2”)以及一 个头部(“header1”)。
总结
本文就rest-assured的基本功能进行举例说明,其中例子大多来自于官方文档,同时我也建议大家多去阅读该开 发文档,其中有很多我们没有讲到的东西。 本文参考: rest-assured官网:Usage · rest-assured/rest-assured Wiki · GitHub rest-assured介绍:IBM Developer get与post的区别:GET和POST两种基本请求方法的区别 - 在途中# - 博客园
使用specification:rest-assured的默认值与Specification重用 - lwjnicole - 博客园