一、静态导入

  为了有效的使用rest-assured,官网推荐从下列class中静态导入方法:

 io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*

如果想使用  Json Schema validation(验证),还需要静态导入下面的方法:

 io.restassured.module.jsv.JsonSchemaValidator.*

如果我们正在使用的是 Spring MVC ,我们可以使用 spring--mock-mvc模型的rest-assured DSL来对Spring 的controllers层进行单元测试。为此我们需要从 RestAssuredMockMvc 中导入下面的方法,还不是从 io.restassured.RestAssured 导入:

 io.restassured.module.mockmvc.RestAssuredMockMvc.*

二、使用实例

1.Json实例

假设 GET请求(to http://localhost:8080/lotto)返回下面的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]
}]
}
}

rest-assured可以非常简单的发起这个GET请求并且验证响应结果,比如:我们想验证 lottoId 是否等于 5 ,可以这样做:

 get("/lotto").then().body("lotto.lottoId",equalTo(5));

或者我们想验证 winnerId的值是否是23,54 :

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

值得注意的是:equalTo()方法和 hasItems()方法是属于 Hamcrest matchers 的方法,所有我们需要静态导入 org.hamcrest.Matchers 。

注意:"json path" 使用 Groovy's GPath 标记法,不要与 Jayway's JsonPath 混淆。

2.以BigDecimal形式返回 floats 和 doubles

  我们可以对rest-assured和JsonPath进行配置,使之以BigDecimal形式返回json里的数值类型数据,而不是返回 floats 和 doubles,参照下面的json:

 {

     "price":12.12 

 }

默认情况下,我们验证 price的值是否等于12.12时是这样做的:

 get("/price").then().body("price", is(12.12f));

但是如果我们喜欢的话,我们可以通过JsonConfig 来配置rest-assured使之以BigDecimal形式返回json里的数值类型数据:

 given().
config(RestAssured.config().jsonConfig(jsonConfig().numberReturnType(BIG_DECIMAL))).
when().
get("/price").
then().
body("price", is(new BigDecimal(12.12));

3.匿名JSON根节点验证

  一个json文本并不一定有一个命名好的根节点属性,验证这种类型的json,这里有一个例子:

 [1, 2, 3]

一个匿名的json根路径要验证的话,可以使用 $ 或者是 空字符串 来验证。例如,我们访问 http://localhost:8080/json ,然后通过rest-assured来验证:

 //第一种方式,使用 $ 代替根节点
get("/json").then().body("$",hasItems(1,2,3)); //第二种方式,使用 空字符串 代替根节点
get("/json").then().body("",hasItems(1,2,3));

4.XML实例

  XML可以使用同样的方式来验证。假设向 http://localhost:8080/greetXML 发送一个POST请求,并且返回下面的xml:

 <greeting>
<firstName>{params("firstName")}</firstName>
<lastName>{params("lastName")}</lastName>
</greeting>

上面的例子返回了一个基于 firstName 和 lastName 请求参数的greeting节点,我们可以通过rest-assured非常简单展示和验证,比如验证 firstName :

 given().
parameters("firstName", "John", "lastName", "Doe").
when().
post("/greetXML").
then().
body("greeting.firstName", equalTo("John")).

如果我们想同时验证  firstName 和 lastName ,我们可以这样写:

 given().
parameters("firstName", "John", "lastName", "Doe").
when().
post("/greetXML").
then().
body("greeting.firstName", equalTo("John")).
body("greeting.lastName", equalTo("Doe"));

或者是使用简单的写法:

 with().parameters("firstName", "John", "lastName", "Doe").when().post("/greetXML").then().body("greeting.firstName", equalTo("John"), "greeting.lastName", equalTo("Doe"));

5.XML命名空间

  为了使响应断言把命名空间考虑在内,我们需要使用  io.restassured.config.XmlConfig 定义一个命名空间。例如,这里有一个叫做 namespace-example 的资源位于 http://localhost:8080,返回下面的XML:

 <foo xmlns:ns="http://localhost/">
<bar>sudo </bar>
<ns:bar>make me a sandwich!</ns:bar>
</foo>

我们可以申明 http://localhost:8080 这个uri并且验证响应结果:

 given().
config(RestAssured.config().xmlConfig(xmlConfig().declareNamespace("test", "http://localhost/"))).
when().
get("/namespace-example").
then().
body("foo.bar.text()", equalTo("sudo make me a sandwich!")).
body(":foo.:bar.text()", equalTo("sudo ")).
body("foo.test:bar.text()", equalTo("make me a sandwich!"));

这个路径的语法遵循的是 Groovy's XmlSlurper 语法,需要注意的是一直到2.6.0版本,路径语法都不支持 Groovy's XmlSlurper 语法。请看  release notes  查看2.6.0之前的语法。

6.XPath

  我们也可以通过使用X-Path 来验证XML响应结果,比如:

 given().parameters("firstName", "John", "lastName", "Doe").when().post("/greetXML").then().body(hasXPath("/greeting/firstName", containsString("Jo")));

或者:

 given().parameters("firstName", "John", "lastName", "Doe").post("/greetXML").then().body(hasXPath("/greeting/firstName[text()='John']"));

如果需要在XPath表达式里面使用命名空间的话,需要在配置中启用这些选项:

 given().
config(RestAssured.config().xmlConfig(xmlConfig().with().namespaceAware(true))).
when().
get("/package-db-xml").
then().
body(hasXPath("/db:package-database", namespaceContext));

namespaceContext是一个javax.xml.namespace.NamespaceContext 的实例 。

三、高级使用实例(复杂的解析以及验证)

  这正是rest-assured的闪光点所在,因为rest-assured实现了Groovy,rest-assured从 Groovy 的API中获得了很大的好处。让我们先从 Groovy 的例子来看:

 def words = ['ant', 'buffalo', 'cat', 'dinosaur']
def wordsWithSizeGreaterThanFour = words.findAll { it.length() > 4 }

  第一行代码我们只是简单定义了一个包含字符的list集合,第二行代码非常的有趣。第二行代码中我们通过Groovy闭包调用 findAll 方法来查询list集合中所有长度大于4的字符。这个闭包中有一个叫 it 的内部变量,这个 it 就代表了list集合中的当前元素。这段代码的结果是一个新的list集合:wordsWithSizeGreaterThanFour ,包含 buffalo and dinosaur。

  下面有一些有趣的方法,也可以在 Groovy 集合中使用:

  • find  ------ 查找第一个匹配闭包断言(closure predicate)的元素
  • collect   ------封装集合中的每一个元素调用闭包的返回值
  • sum  -------集合中所有元素之和
  • max/min  --------返回集合中的最大值或最小值

那么我们在验证XML和Json时,如何应用这些优点呢???

1.XML例子

  例如,我们有个资源 http://localhost:8080/shopping 返回下面的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>

接下来我们要写一个test方法来验证 类型为 groceries 的category节点是否包含 Chocolate和Coffee两个元素,在rest-assured中我们可以这么写:

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

那么上面的例子当中发生了什么呢?首先使用XPath方法 shopping.category 获取所有的category的一个list集合,在这个list集合中我们调用 find 方法,返回type属性值等于"groceries"的单个category节点,在这个category节点中我们继续获得了所有item元素。从上面可以看出category节点下不止一个item元素,所以会返回一个list集合,然后我们通过Hamcrest matcher 的 hasitems 方法来验证这个list。这就是上面这个例子整个执行过程!

  但是如果我们想获得上面的item,然后又不想使用 Hamcrest matcher 的 hasitems 方法来验证,那么我们可以使用XmlPath:

 // 获得response,并且以字符串输出
String response = get("/shopping").asString();
// 从response中获得groceries,"from"是从XmlPath类中静态导入的
List<String> groceries = from(response).getList("shopping.category.find { it.@type == 'groceries' }.item");

如果在response中我们仅仅关心的是 groceries ,我们还可以这样做:

 // 获得response,并以字符串形式输出
List<String> groceries = get("/shopping").path("shopping.category.find { it.@type == 'groceries' }.item");

1.1 深度优先搜索

  事实上,前面的例子我们还可以进一步简化一下:

 when().
get("/shopping").
then().
body("**.find { it.@type == 'groceries' }", hasItems("Chocolate", "Coffee"));

  ** 是一种在XML文件中做深度搜索的捷径。我们搜索第一个具有type属性值等于"groceries"的节点,注意我们并没有在"item"这个Xml路径结束,原因是在category节点返回item值的list集合时toString() 方法被自动调用了。

2.JSON例子

  例如,我们有个资源 http://localhost:8080/store 返回下面的JSON:

 {
"store":{
"book":[
{
"author":"Nigel Rees",
"category":"reference",
"price":8.95,
"title":"Sayings of the Century"
},
{
"author":"Evelyn Waugh",
"category":"fiction",
"price":12.99,
"title":"Sword of Honour"
},
{
"author":"Herman Melville",
"category":"fiction",
"isbn":"0-553-21311-3",
"price":8.99,
"title":"Moby Dick"
},
{
"author":"J. R. R. Tolkien",
"category":"fiction",
"isbn":"0-395-19395-8",
"price":22.99,
"title":"The Lord of the Rings"
}
]
}
}

例1,我们发起一个请求"/store",并且断言:book的价格(price)小于10的title,是否包含"Sayings of the Century" 和 "Moby Dick"两个元素:

 get("/store").then().body("store.book.findAll{it.price<10}.title",hasItems("Sayings of the Century","Moby Dick"));

跟上面Xml的例子,我们首先使用闭包来查找所有符合价格(price)小于10的books,然后返回books的titles集合。接着我们使用 hasItems 方法来断言我们期望获得的titles。如果使用JsonPath返回这个titles,我们可以使用下面的方式来代替:

 //以字符串形式输出response
Response response = get("/store").asString();
//从response中获得所有price<10的book,"from"是从JsonPath类中静态导入的
List<String> titles = from(response).getList("store.book.findAll{it.price<10}.title");

例2,我们来考虑下如果我们想要断言:所有author字段值长度的总和是否大于50。这看起来是一个难以回答的问题,这也正显示了闭包(closures)和Groovy集合的强大之处。在rest-assured中我们可以这样做:

 when().
get("/store").
then().
body("store.book.author.collect{it.length()}.sum()",greaterThan(50));

  首先我们通过 store.book.author 获得了所有的authors字段值并返回一个authors集合,然后我们调用 collect 方法来封装通过闭包的 it.length() 方法获得的每个元素的长度值,it.length方法的作用是:对列表里的每一个author都会执行一次length()方法,使用collect方法后返回一个新的list集合。在这个新的list集合我们调用 sum() 方法求所有长度之和。上面和的结果为53,然后我们使用 greateThan() 方法断言长度之和是否大于50。

  事实上,上面的例子我们还可以做进一步的简化,让我们再来看一下 "words" 这个例子:

 def words = ['ant', 'buffalo', 'cat', 'dinosaur']

Groovy 有一个非常方便的方式用来遍历集合中的每一个元素,使用展开操作符( *. )来操作:

 def words = ['ant', 'buffalo', 'cat', 'dinosaur']
assert [3, 6, 3, 8] == words*.length()

Groovy 返回了一个新的包含words中每个元素长度值的集合。我们也可以在rest-assured中应用这个方法在author上:

 when().
get("/store");
then().
body("store.book.author*.length().sum()", greaterThan(50)).

当然,我们也可以使用JsonPath来获得这个结果:

 // 以字符串形式输出response
String response = get("/store").asString();
// 获得author字段值长度的和, "from" 是从JsonPath类中静态导入的
int sumOfAllAuthorLengths = from(response).getInt("store.book.author*.length().sum()");
// 断言
assertThat(sumOfAllAuthorLengths, is(53));

rest-assured之静态导入及简单使用实例的更多相关文章

  1. 动态导入(import)和静态导入(import)的区别

    import static静态导入是JDK1.5中的新特性.一般我们导入一个类都用 import com.....ClassName;而静态导入是这样:import static com.....Cl ...

  2. static特别用法【静态导包】——Java包的静态导入

    面试我问你static关键字有哪些作用,如果你答出static修饰变量.修饰方法我会认为你合格,答出静态块,我会认为你不错,答出静态内部类我会认为你很好,答出静态导包我会对你很满意,因为能看出你非常热 ...

  3. JAVA静态导入(inport static)详解

    在Java 5中,import语句得到了增强,以便提供甚至更加强大的减少击键次数功能,虽然一些人争议说这是以可读性为代价的.这种新的特性成为静态导入. 当你想使用static成员时,可以使用静态导入( ...

  4. 2017.12.19 Java包的静态导入import static和import的区别

    import static静态导入是JDK1.5中的新特性.一般我们导入一个类都用 import com-..ClassName;而静态导入是这样:import static com-..ClassN ...

  5. java5的静态导入import static

    在Java 5中,import语句得到了增强,以便提供甚至更加强大的减少击键次数功能,虽然一些人争议说这是以可读性为代价的.这种新的特性成为静态导入. 1.静态导入的与普通import的区别: imp ...

  6. 提高你的Java代码质量吧:少用静态导入

    一.分析  从Java 5开始引入静态导入语法(import static),其目的是为了减少字符输入量,提高代码的可阅读性,以便更好地理解程序. 但是,滥用静态导入会使程序更难阅读,更难维护.静态导 ...

  7. Jsp的include指令静态导入和动态导入的区别

    1.什么是静态导入? 静态导入指的是,将一个外部文件嵌入到当前JSP文件中,同时解析这个页面的JSP语句,它会把目标页面的其他编译指令也包含进来. include的静态导入指令使用语法: <%@ ...

  8. Java学习笔记(三)——静态导入,package-info,Fall-through

    [前面的话] 算是真正的放松了好几天时间,没有看任何书,没有任何任务,今天是过完年后的第一天上班时间,我又开始了我的学习之路,感觉还没有老,怎么心态越来越平静了,进入工作状态,就好好努力工作,新的一年 ...

  9. jsp里面include的静态导入和动态导入的区别

    静态导入就是将被导入页面完全融入到导入的页面中:而动态导入只是在servlet里面插入了include方法,导入的这是被导入页面的body标签里面的内容 1.什么是静态导入? 静态导入指的是,将一个外 ...

随机推荐

  1. SpringCloud03 Ribbon知识点、 Feign知识点、利用RestTemplate+Ribbon调用远程服务提供的资源、利用feign调用远程服务提供的资源、熔断

    1 远程服务资源的调用 1.1 古老的套路 在微服务出现之前,所有的远程服务资源必须通过RestTemplate或者HttpClient进行:但是这两者仅仅实现了远程服务资源的调用,并未提供负载均衡实 ...

  2. Yii2中ACF和RBAC

    ACF ( Access Control Filter) ACF ( Access Control Filter)官网的解释就是一个可以在模型或控制器执行行为过滤器,当有用户请求时,ACF将检查acc ...

  3. 数据库MySQL之 视图、触发器、存储过程、函数、事务、数据库锁、数据库备份、事件

    数据库MySQL之 视图.触发器.存储过程.函数.事务.数据库锁.数据库备份.事件 浏览目录 视图 触发器 存储过程 函数 事务 数据库锁 数据库备份 事件 一.视图 1.视图概念 视图是一个虚拟表, ...

  4. CLR VIA C# 泛型的协变和逆变

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. C#使用var定义变量时的四个特点

    使用var定义变量时有以下四个特点: 1. 必须在定义时初始化.也就是必须是var s = “abcd”形式: 2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了. 3.   var要求是 ...

  6. h5存储的优点

    1.解决4k大小问题2.解决请求头常带存储信息的问题3.解决关系型存储问题4.可以跨浏览器

  7. ubuntu14.04LTS下制作安装启动U盘

    ubuntu自带的启动U盘制作工具在我的非UEFI电脑上无法启动,找到一个国产的好用东西:深度deepin-boot-maker. 下载地址(官方百度盘):点击下载 用起来也很简单,只需要选择下载好的 ...

  8. Windows 下 MongoDb 简单配置

    以管理员的启动cmd        进入安装目录下                      输入:  mongod  --auth --port 3406  --dbpath=库地址  --logp ...

  9. C#7.0连接MySQL8.0数据库的小笔记

    1.要连接MySql数据库必须首先下载MySql官方的连接.net的文件,文件下载地址为https://dev.mysql.com/downloads/connector/net/6.6.html#d ...

  10. 从头开始学eShopOnContainers——开发环境要求

    一.简介 eShopOnContainers是一个简化版的基于.NET Core和Docker等技术开发的面向微服务架构的参考应用,是一个简化版的在线商城/电子商务应用,其包含基于浏览器的Web应用. ...