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));

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM