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() 方法被自動調用了。
rest-assured之靜態導入及簡單使用實例