一、静态导入

  为了有效的使用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. 图论算法》关于tarjan算法两三事

    关于tarjan,在下觉得这个算法从本质上是一种暴力求强连通分量的方法,但事实上这也是最有效的求强连通分量的方法之一,它对于处理各种强连通分量中奇怪问题,都可以直接转化,所以比较通用和常见. 什么是t ...

  2. c++ 多态问题(在虚函数里调用虚函数)

    最近在看cocos2d-x的源码,非常感激cocos2d作者的开源精神.在看代码的过程中感觉两个方向让我受益,1.把之前从书中看到的c++知识,明白了怎么运用.2.学习作者驾驭代码的巧妙方法. 看co ...

  3. 581. Shortest Unsorted Continuous Subarray连续数组中的递增异常情况

    [抄题]: Given an integer array, you need to find one continuous subarray that if you only sort this su ...

  4. 11.BETWEEN 操作符

    BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEEN 操作符 操作符 BETWEEN ... AND 会选取介于两个值之间的数据范围.这些值可以是数值 ...

  5. Luogu 1379 八数码难题

    吐槽:此题就是一点一点卡过去的 警告: 1.千万不能用dfs搜这种东西(dfs需要遍历所有状态才能找到最优解), 分分钟爆炸 2.写结构体的时候要综合判断&的加和不加 Code: // luo ...

  6. Flask框架 之 路由和视图详解

    路由+视图 我们之前了解了路由系统是由带参数的装饰器完成的. 路由本质:装饰器和闭包实现的. 路由设置的两种方式 来看个例子. @app.route('/index') def index(): re ...

  7. OVS的初始配置

    1.去掉bridge模块,为下面用OVS的模块奠定基础 rmmod bridge .insmod datapath/linux/openvswitch_mod.ko .insmod datapath/ ...

  8. cbv+resful+APIView源码分析

    CBV源码分析 1概念:什么是cbv和fbv 已经什么是API class bass View ---基于类的视图 function bass View ---基于函数的视图 API(Applicat ...

  9. (转)使用Jquery+EasyUI 进行框架项目开发案例讲解之一 员工管理源码分享

    原文地址:http://www.cnblogs.com/huyong/p/3334848.html 在开始讲解之前,我们先来看一下什么是Jquery EasyUI?jQuery EasyUI是一组基于 ...

  10. Kernel的意义

    在第7章最后一段讲到Kernel,Kernel就是用向量表示元素的和的乘积. Back in our discussion of linear regression, we had a problem ...