• rest-assured之静态导入及简单使用实例


    一、静态导入

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

    1 io.restassured.RestAssured.*
    2 io.restassured.matcher.RestAssuredMatchers.*
    3 org.hamcrest.Matchers.*

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

    1 io.restassured.module.jsv.JsonSchemaValidator.*

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

    1 io.restassured.module.mockmvc.RestAssuredMockMvc.*

    二、使用实例

    1.Json实例

    假设 GET请求(to http://localhost:8080/lotto)返回下面的Json:

     1 {
     2 "lotto":{
     3  "lottoId":5,
     4  "winning-numbers":[2,45,34,23,7,5,3],
     5  "winners":[{
     6    "winnerId":23,
     7    "numbers":[2,45,34,23,3,5]
     8  },{
     9    "winnerId":54,
    10    "numbers":[52,3,12,11,18,22]
    11  }]
    12 }
    13 }

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

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

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

    1 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:

    1 {
    2 
    3     "price":12.12 
    4 
    5 }

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

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

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

    1 given().
    2         config(RestAssured.config().jsonConfig(jsonConfig().numberReturnType(BIG_DECIMAL))).
    3 when().
    4         get("/price").
    5 then().
    6         body("price", is(new BigDecimal(12.12));

    3.匿名JSON根节点验证

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

    1 [1, 2, 3]

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

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

    4.XML实例

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

    1 <greeting>
    2    <firstName>{params("firstName")}</firstName>
    3    <lastName>{params("lastName")}</lastName>
    4 </greeting>

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

    1 given().
    2          parameters("firstName", "John", "lastName", "Doe").
    3 when().
    4          post("/greetXML").
    5 then().
    6          body("greeting.firstName", equalTo("John")).

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

    1 given().
    2          parameters("firstName", "John", "lastName", "Doe").
    3 when().
    4          post("/greetXML").
    5 then().
    6          body("greeting.firstName", equalTo("John")).
    7          body("greeting.lastName", equalTo("Doe"));

    或者是使用简单的写法:

    1 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:

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

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

    1 given().
    2         config(RestAssured.config().xmlConfig(xmlConfig().declareNamespace("test", "http://localhost/"))).
    3 when().
    4          get("/namespace-example").
    5 then().
    6          body("foo.bar.text()", equalTo("sudo make me a sandwich!")).
    7          body(":foo.:bar.text()", equalTo("sudo ")).
    8          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响应结果,比如:

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

    或者:

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

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

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

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

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

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

    1 def words = ['ant', 'buffalo', 'cat', 'dinosaur']
    2 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:

     1 <shopping>
     2       <category type="groceries">
     3         <item>Chocolate</item>
     4         <item>Coffee</item>
     5       </category>
     6       <category type="supplies">
     7         <item>Paper</item>
     8         <item quantity="4">Pens</item>
     9       </category>
    10       <category type="present">
    11         <item when="Aug 10">Kathryn's Birthday</item>
    12       </category>
    13 </shopping>

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

    1 when().
    2        get("/shopping").
    3 then().
    4        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:

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

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

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

    1.1 深度优先搜索

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

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

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

    2.JSON例子

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

     1 {  
     2    "store":{  
     3       "book":[  
     4          {  
     5             "author":"Nigel Rees",
     6             "category":"reference",
     7             "price":8.95,
     8             "title":"Sayings of the Century"
     9          },
    10          {  
    11             "author":"Evelyn Waugh",
    12             "category":"fiction",
    13             "price":12.99,
    14             "title":"Sword of Honour"
    15          },
    16          {  
    17             "author":"Herman Melville",
    18             "category":"fiction",
    19             "isbn":"0-553-21311-3",
    20             "price":8.99,
    21             "title":"Moby Dick"
    22          },
    23          {  
    24             "author":"J. R. R. Tolkien",
    25             "category":"fiction",
    26             "isbn":"0-395-19395-8",
    27             "price":22.99,
    28             "title":"The Lord of the Rings"
    29          }
    30       ]
    31    }
    32 }

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

    1 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,我们可以使用下面的方式来代替:

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

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

    1 when().
    2     get("/store").
    3 then().
    4     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" 这个例子:

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

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

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

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

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

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

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

      

  • 相关阅读:
    Spring Cloud Feign 在调用接口类上,配置熔断 fallback后,输出异常
    Spring Cloud Feign 输出日志
    RestTemplate OR Spring Cloud Feign 上传文件
    Springboot swagger2 导出api文档
    springboot + swagger2 生成api文档
    网页输出日志文件
    Mybatis Common Mapper文件
    Java 序列化工具类
    rabbitMQ的三种路由模式
    .net mvc中session的锁机制
  • 原文地址:https://www.cnblogs.com/lwjnicole/p/8289844.html
Copyright © 2020-2023  润新知