02-接口自動化框架REST Assured的斷言實現

1、Json斷言

1.1 環境準備

這裏以rest-assured官方給的一個示例做演示學習

{
"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]
 }]
}
}

在本地使用python -m CGIHTTPServer臨時搭建起一個服務:
在這裏插入圖片描述

1.2 JsonPath(Groovy’s GPath)

在Groovy的官網,雖然並未提及它在json中的使用,但實際上只要是樹形的層級關係,無論是jsonxml或者其他格式,就可以使用這種簡單的語法幫我們去找到其中的值,rest-assured也已經幫我們實現支持了GPath的斷言方式

  • 根節點.子節點
    1)我們可以使用根節點.(點)子節點的方式一層層的找下去,例如我們需要對lottoId等於5進行斷言:
    在這裏插入圖片描述
    @Test
    void testGPath(){
         given().
         when().
                 log().all().get("http://127.0.0.1:8000/restAssured.json").
         then().
                 log().all().body("lotto.lottoId",equalTo(5));
     }
    
    2)如果我們想要斷言winners數組下面的winnerId,檢查23和54是否包含其中,可以如下lotto.winners.winnerId寫法
    在這裏插入圖片描述
    @Test
    void testGPath(){
        given().
        when().
                log().all().get("http://127.0.0.1:8000/restAssured.json").
        then().
                log().all()
                .body("lotto.winners.winnerId",hasItems(54,23));
    }
    
    • 索引取值
      1)如果我們想要取某些相同字段中的某一個,可以使用類似索引的方式獲取,例如想要斷言winners數組下面的winnerId的第一個值是否爲23,可以使用lotto.winners.winnerId[0],寫法如下:
      在這裏插入圖片描述
    @Test
    void testGPath(){
        given().
        when().
                log().all().get("http://127.0.0.1:8000/restAssured.json").
        then().
                log().all()
                .body("lotto.winners.winnerId[0]",equalTo(23));
    }
    
    2)如果我們想要取某些相同字段中的最後一個,可以使用-1作爲索引,例如斷言斷言winners數組下面的winnerId的最後一個的值是否爲54
    在這裏插入圖片描述
    @Test
    void testGPath(){
        given().
        when().
                log().all().get("http://127.0.0.1:8000/restAssured.json").
        then().
                log().all()
                .body("lotto.winners.winnerId[-1]",equalTo(54));
    }
    
    • findAll
      有時候我們需要獲取符合某些條件的結果來進行斷言,這裏findAll可以幫助我們實現,我們可以在findAll方法中寫篩選條件,例如我們想取winnerId的值在大於或等於30小於60之間的結果進行斷言,具體寫法如下:
    @Test
    void testGPath(){
        given().
        when().
                log().all().get("http://127.0.0.1:8000/restAssured.json").
        then().
                log().all()
                .body("lotto.winners.findAll{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId[0]",equalTo(54));
    }
    
    • find
      find的用法與findAll基本一致,只是find默認取匹配到的第一個:
    @Test
    void testGPath(){
        given().
        when().
                log().all().get("http://127.0.0.1:8000/restAssured.json").
        then().
                log().all()
                .body("lotto.winners.find{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId",equalTo(54));
        }
    

1.3 實操演示

將上述各個斷言語法寫在一起,實際運行校驗結果:
在這裏插入圖片描述

2、XML斷言

2.1 環境準備

上面介紹了,GPath也支持XML格式的斷言,這裏再以rest-assured官方給的一個實例做演示

<shopping>
 <category type="groceries">
 <item>
 <name>Chocolate</name>
 <price>10</price>
 </item>
 <item>
 <name>Coffee</name>
 <price>20</price>
 </item>
 </category>
 <category type="supplies">
 <item>
 <name>Paper</name>
 <price>5</price>
 </item>
 <item quantity="4">
 <name>Pens</name>
 <price>15</price>
 </item>
 </category>
 <category type="present">
 <item when="Aug 10">
 <name>Kathryn's Birthday</name>
 <price>200</price>
 </item>
 </category>
 </shopping>

再次在本地搭起一個臨時服務:
在這裏插入圖片描述

2.2 XmlPath斷言語法

  • 若我們要對第二個name的值Coffee進行斷言,寫法如下:
    在這裏插入圖片描述
    @Test
    void testXML(){
        when().
                get("http://127.0.0.1:8000/restAssured.xml").
        then().
                log().all().
                body("shopping.category[0].item[1].name",equalTo("Coffee"));
    }
    
  • size()
    可以利用size()方法來獲取對應節點的數量,例如這裏要斷言category的數量:
    @Test
    void testXML(){
        when().
                get("http://127.0.0.1:8000/restAssured.xml").
        then().
                log().all()
                .body("shopping.category.size()",equalTo(3));
    }
    
  • it.@typeit.price
    在xml中斷言中,可以利用it.屬性或節點的值來作爲篩選條件;
    例如這裏要獲取typesuppliescategory下的第一個itemname
    以及獲取price爲10的商品名name
    在這裏插入圖片描述
    @Test
    void testXML(){
         when().
                 get("http://127.0.0.1:8000/restAssured.xml").
         then().
                 log().all()
                 .body("shopping.category.findAll{ it.@type == 'supplies' }.item[0].name",equalTo("Paper"))
                 .body("shopping.category.item.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
     }
    
  • **.findAll
    對於xml中有一個特別的語法,**.findAll,可以直接忽略前面的節點,直接對篩選條件進行匹配,依然獲取price爲10的商品名name,寫法如下:
    @Test
    void testXML(){
        when().
                get("http://127.0.0.1:8000/restAssured.xml").
        then().
                log().all()
                .body("**.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
    }
    

2.3 實操演示

將上述各個斷言語法寫在一起,實際運行校驗結果:
在這裏插入圖片描述

3、JsonSchema斷言

3.1 需求背景

在實際工作中,對接口返回值進行斷言校驗,除了常用字段的斷言檢測以外,還要對其他字段的類型進行檢測,原因在於:

  • 1、返回字段較多,無法保證每個字段都寫斷言
  • 2、防止客戶端未做null值的校驗判斷,如果因爲版本變更或網絡等原因造成某個不能接收null值的返回字段爲null,就很有可能造成軟件的崩潰
  • 3、某些數值是不能爲負的
  • 4、小數點保留位數,對於股票的交易、醫療數據的分析,小數點的精確度都是有其實際價值的

對返回的字段一個個寫斷言顯然是非常耗時的,這個時候就需要一個模板,可以定義好數據類型和匹配條件,除了關鍵參數外,其餘可直接通過此模板來斷言,這個就要請出JsonSchema

3.2 使用方法

先對上述的json例子做少許修改,增加一個String類型的winnername字段,這裏可以先你不用疑惑爲什麼加,後續自有其演示作用
在這裏插入圖片描述

3.2.1 JsonSchema模板生成

1)首先要藉助於Json schema tool的網站https://www.jsonschema.net/,將返回json字符串複製到頁面左邊,然後點擊INFER SHCEMA,就會自動轉換爲schema json文件類型,會將每個地段的返回值類型都設置一個默認類型;
pattern中也可以寫正則進行匹配
在這裏插入圖片描述
2)點擊“設置”按鈕會出現各個類型返回值更詳細的斷言設置,這個就是schema最常用也是最實用的功能,也可以對每種類型的字段最更細化的區間值校驗或者斷言,例如長度,取值範圍等,具體感興趣的話可以從官網學習深入學習;平常對重要字段的校驗我通常會選用其他斷言,比如hamcrest斷言
在這裏插入圖片描述
3)選擇複製功能,可以將生成的schema模板保存下來
在這裏插入圖片描述

3.2.2 rest-assured結合使用

4)添加maven依賴,在rest-assured完成支持

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>4.0.0</version>
</dependency>

5)使用matchesJsonSchemaInClasspath方法對響應結果進行schema斷言

@Test
void jsonSchemaTest(){
    get("http://127.0.0.1:8000/restAssured.json").
    then().log().all()
            .body(matchesJsonSchemaInClasspath("jsonSchema.json"));
}

運行結果:
在這裏插入圖片描述

3.2.3 多類型校驗-Combining schemas
  • String類型的默認值爲null,後端很有可能在某個字段無值時返回null,例如我們將之前添加的winnername字段返回null:
    在這裏插入圖片描述
    運行查看斷言結果:
    在這裏插入圖片描述
    很明顯用例執行失敗,當我們定義了winnernameString類型後,返回null就會斷言失敗,這顯然不符合我們的需求,會造成用例執行結果的誤判,這個時候我們需要使winnername即可以爲String類型,又可以爲null

  • 這就要用到jsonSchema提供的Combining schemas方法了
    Combining schemas提供瞭如下幾種方式:

    • allOf
    • anyOf
    • oneOf
    • not
  • 這裏我們選取anyOf(任何一項滿足即可)來完成上述的舉例,將原來的type換成Stringnull任何一個都支持的類型:
    在這裏插入圖片描述
    再次運行用例,查看斷言結果:
    在這裏插入圖片描述
    用例完美通過,到此結束~

4、寫在最後

斷言的語法不止上述列出的這些,但是日常工作中絕大部分需求都可以滿足,如有需要可參考官方文檔進去研究:
JsonPath:
https://www.javadoc.io/doc/io.rest-assured/json-path/latest/io/restassured/path/json/JsonPath.html
XmlPath:
https://www.javadoc.io/doc/io.rest-assured/xml-path/latest/io/restassured/path/xml/XmlPath.html
JsonSchema:
https://json-schema.org/understanding-json-schema/

另外,在我們實際工作中,很多時候並不是直接對響應結果直接斷言,我們可能需要獲取響應結果中的某些值,將這些值傳遞到下一個接口或者和其他接口的響應進行比較斷言,這就涉及到了對響應response的獲取與處理了,可參考另一篇文章:
03-接口自動化框架REST Assured對Response結果的導出獲取

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章