其餘API測試|| RestAssured快速指南2020教程

用於Rest API測試自動化的Rest Assured API測試

RestAssured-放心教程api測試
安心的API自動化

在本詳盡的“放心的放心”教程中,我們將學習 深入的REST API測試,API測試自動化以及模塊化方法中的REST保證

什麼是RestAssured及其使用

Rest Assured是用於REST API自動化測試的一種非常廣泛使用的開源技術,該技術基於基於J​​ava的庫。

Rest Assured在無頭客戶端模式下與Rest API進行交互,我們可以通過添加不同的層以形成請求並通過不同的HTTPS動詞向服務器創建HTTP請求來增強相同的請求。

內置的Rest Assured庫提供了大量方法和實用程序,用於驗證從服務器接收到的響應,例如狀態消息,狀態代碼和響應正文。

此完整的REST API自動化測試的“放心的教程”完整系列包括以下主題:

入門:使用Build工具(即Maven / gradle)配置restAssured

步驟1:如果您正在使用Maven,只需在pom.xml中添加以下依賴項(您也可以選擇任何其他版本):

要開始使用REST Assured,只需將依賴項添加到項目中。 


    io.rest-assured
    放心
    4.3.0
    測試

如果使用gradle,只需在build.gradle中添加以下內容(同樣,您也可以選擇任何其他版本):

testCompile組:“ io.rest-assured”,名稱:“ rest-assured”,版本:“ 4.3.0”

步驟2:REST Assured可以很容易地與現有的單元測試框架(例如Testng,JUnit)集成並使用

在這裡,我們根據單元測試框架使用testNg。

導入Rest Assured的庫後,我們需要將以下靜態導入添加到我們的測試類中:

導入靜態io.restassured.RestAssured。*;

導入靜態org.hamcrest.Matchers。*;

注意: 為此,我們將測試Ergast Developer API, 可以在這裡找到。 該API提供與一級方程式比賽,驅動程序,電路等相關的歷史數據。

熟悉語法:

放心使用支持BDD格式(小黃瓜語法)編寫測試腳本,即以Given / When / Then / And格式編寫,我們假設您已經了解BDD / gherkin語法,否則請建議花30分鐘的時間來了解什麼是BDD(小黃瓜語法)以及它的工作原理和基本原理。

T-01: 我們的第一個腳本基本上是使用此API來驗證1年F1中的電路數量(http://ergast.com/api/f1/2017/circuits.json)

@Test(description =“ 2017賽季的電路數量應為20”)public void validateratingNumberOfCircuits(){Given()。when()。get(“ http://ergast.com/api/f1/2017/circuits。 json”)。 then()。assertThat()。body(“ MRData.CircuitTable.Circuits.circuitId”,hasSize(20)); }

其餘API響應驗證 :

1.捕獲API請求的JSON響應。

2.使用GPath表達式“ MRData.CircuitTable.Circuits.circuitId”查詢circuitId

3.驗證circuitId元素集合的大小為20

在這裡我們正在使用 Hamcrest匹配器 用於各種驗證,例如

  • equalTo()驗證相等性
  • 用於比較驗證的lessThan()和GreaterThan()方法,
  • hasItem()方法用於驗證元素集合中元素的存在。

還有各種其他方法可用於執行某些驗證。

您還可以參考Hamcrest庫文檔以獲取匹配器和方法的完整列表。

驗證響應代碼:

Given()。when()。get(“http://ergast.com/api/f1/2017/circuits.json“).then()。assertThat()。statusCode(200);

內容類型驗證

給定().when()。get(“ http://ergast.com/api/f1/2017/circuits.json”).then()。assertThat()。contentType(ContentType.JSON);

驗證標題“ Content-Length”

Given()。when()。get(“http://ergast.com/api/f1/2017/circuits.json“).then()。assertThat()。header(” Content-Length“,equalTo(” 4551“));

在單個測試中的多重驗證為(通過使用and()方法):

@Test(description =“ 2017賽季的電路數應為20”)
    公共無效validatingNumberOfCircuits(){
        給定().when()。get(“ http://ergast.com/api/f1/2017/circuits.json”).then()。assertThat()。header(“ Content-Length”,equalTo(“ 4551“))。and()。statusCode(200);
    }

驗證響應正文元素/屬性:

我們可以使用JsonPath來獲取json屬性的值,並使用TestNg進行斷言

@Test(description =“系列名稱驗證為f1”)
    公共無效的validatingSeriesName(){
        //將ResponseBody轉換為String
        字符串responseBody = given()。when()。get(“ http://ergast.com/api/f1/2017/circuits.json”).getBody()。asString();
        //通過將響應主體作為字符串傳遞來創建JsonPath對象
        JsonPath resJson =新的JsonPath(responseBody);
        //在MRData下獲取屬性值系列
        字符串seriesName = resJson.getString(“ MRData.series”);
        //用戶TestNg斷言
        Assert.assertEquals(“ f1”,seriesName);
    }

以類似的方式,我們可以使用XMLPath獲得XML響應的價值。在這裡,我們正在使用JSON,因此我們在這裡使用JSonPath

RESTful API僅支持兩種類型的參數:

A. 查詢參數: 這裡的參數附加在API端點的末尾,可以由問號標識,並形成一個鍵值對,例如 

https://www.google.com/search?q=https://www.wikipedia.org/

如果我們要搜索“SOMETHING_ELSE_TEXT'我們可以替換參數的值 'q'與 SOMETHING_ELSE_TEXT代替https://www.wikipedia.org/。

B. 路徑參數: 這些是RESTful API端點的一部分。 

例如。 我們之前使用的端點:http://ergast.com/api/f1/2017/circuits.json,此處的“ 2017”是路徑參數值。

獲得年度結果 2016年,我們可以用2017年取代2016年 然後API將提供2016年的響應正文。

使用針對RestAssured的路徑參數進行測試

@Test(description =“使用路徑參數驗證電路數量”)
    公共無效testWithPathParams(){
        字符串seasonNumber =“ 2017”;
       字符串responseBody = Given()。pathParam(“ season”,seasonNumber).when()。get(“ http://ergast.com/api/f1/{season}/circuits.json”).getBody()。asString ();
        //通過將響應主體作為字符串傳遞來創建JsonPath對象
        JsonPath resJson =新的JsonPath(responseBody);
        //在MRData下獲取屬性值系列
        字符串seriesName = resJson.getString(“ MRData.series”);
        //用戶TestNg斷言
        Assert.assertEquals(“ f1”,seriesName);
    }

使用查詢參數對RestAssured進行測試

@Test(description =“使用查詢參數驗證Google搜索”)
    公共無效testWithPathParams(){
        字符串searchItem =“https://www.wikipedia.org/";
  給定().queryParam(“ q”,searchItem).when()。get(“ https://www.google.com/search”).then()。assertThat()。statusCode(200);
    }

參數化測試:

我們可以使用Rest Assured進行數據驅動的測試(即,相同的測試腳本將使用不同的輸入數據集執行多次,並提供不同的輸出數據) 

步驟1:創建一個testNg數據提供程序。

步驟2:在“測試”腳本中使用數據提供程序。

@DataProvider(name =“ seasonsAndRaceNumbers”)
    公共對象[] [] testDataFeed(){
        返回新的Object [] [] {
                {“ 2017”,20},
                {“ 2016”,21}
        };
    }
@Test(description =“不同季節的電路數量驗證”,dataProvider =“seasonsRaceNumbers“)public void circuitNumberValidation(String seasonYear,int raceNumbers){給定()。pathParam(“ season”,seasonYear).when()。get(“ http://ergast.com/api/f1/{季節}/circuits.json“)。then()。assertThat()。body(” MRData.CircuitTable.Circuits.circuitId“,hasSize(種族數字)); }

使用RestAssured處理多值參數 

多值參數是每個參數名稱具有一個以上值的參數(即每個paramKey的值列表),我們可以像下面這樣處理它們:

給定().param(“ paramKey”,“ paramValue1”,“ paramaValue2”)。when()。get(“ API URL”);

或者我們可以準備一個列表並將該列表作為paramKey的值傳遞,例如:

清單paramValue = new新的ArrayList ();
paramValue.add(“ paramvalue1”);
paramValue.add(“ paramvalue2);
給定().param(“ paramKey”,paramValue).when()。get(“ API URL”);
使用RestAssured處理Cookie 
給定().cookie(“ cookieK”,“ cookieVal”)。when()。get(“ API URL”);

Or 

我們還可以在此處指定一個多值Cookie,例如:

Given()。cookie(“ cookieK”,“ cookieVal1”,“ cookieVal2”)。when()。get(“ API URL”);

使用標題:

我們可以在請求中使用以下標頭來指定:

給定().header(“ headerK1”,“ headerValue1”)。header(“ headerK2”,“ headerValue2”)。when()。get(“ API URL”);

使用contentType:

給定().contentType(“ application / json”)。when()。get(“ API URL”);

Or 

給定().contentType(ContentType.JSON).when()。get();

測量響應時間:

long timeDurationInSeconds = get(“ API URL”)。timeIn(SECONDS);

其餘API身份驗證

REST確保支持不同的身份驗證方案,例如OAuth,摘要,證書,表單和可搶占式基本身份驗證。 我們可以為每個請求設置身份驗證 

這是使用相同的示例請求:

給定().auth()。basic(“ uName”,“ pwd”)。when()。get(“ URL”)..

另一方面,身份驗證並在以下方法中為HTTP請求定義:

RestAssured.authentication = basic(“ uName”,“ pwd”);

基本的AUTH類型:

基本身份驗證有兩種類型,“搶占式”和“挑戰令牌基本身份驗證”。

搶占式基本身份驗證:

即使在某些情況下服務器給出未經授權的響應以及觸發請求之前,這也將發送基本身份驗證憑據,從而減少了進行額外連接的開銷。 除非我們正在測試服務器的挑戰能力,否則這通常是主要發生的情況。 

例如。

給定().auth()。preemptive()。basic(“ uName”,“ pwd”)。when()。get(“ URL”)。then()。statusCode(200);

挑戰基本身份驗證

另一方面,“有挑戰性的基本身份驗證”的“ REST受保證人”將不提供憑據,除非服務器明確提出要求,即服務器拋出未經授權的響應。 在該未經授權的響應之後,Rest-Assured將另一個請求發送到服務器即Auth。

給定().auth()。basic(“ uName”,“ pwd”)。when()。get(“ URL”)。then()。statusCode(200);

摘要身份驗證

到目前為止,僅考慮“具有挑戰性的摘要身份驗證”。 例如:

給定().auth()。digest(“ uName”,“ pwd”)。when()。get(“ URL”)。then()。statusCode(200); 

表格認證

根據應用程序/場景,我們可以通過3種不同的方法來實現這一目標:

表單身份驗證是互聯網上非常流行的一種身份驗證,即用戶正在通過網頁輸入其憑據(即用戶名和密碼)並登錄到系統。 

給定().auth()。form(“ uName”,“ pWd”)。
when()。get(“ URL”);
then()。statusCode(200);

儘管這可能無法達到最佳效果,但取決於網頁的複雜性,它可能會通過或失敗。 更好的選擇是使用以下方法在設置表單身份驗證時提供這些詳細信息:

給定().auth()。form(“ uName”,“ pwd”,新的FormAuthConfig(“ /'此處為表單動作名稱,它是表單標籤html頁面代碼的一部分',” uName“,” pwd “))。when()。get(” URL“)。then()。statusCode(200);

在這種方法中,內部的REST保證人不需要觸發其他請求並通過網頁進行解析。 

如果您使用的是默認的Spring Security,則 預定義的FormAuthConfig被觸發。

給定().auth()。form(“ uName”,“ Pwd”,FormAuthConfig.springSecurity())。when()。get(“ URL”)。then()。statusCode(200);

注意:如果我們要發送其他輸入數據以及表單auth,則可以編寫以下內容:

給定().auth()。form(“ uName”,“ pwd”,formAuthConfig()。withAdditionalFields(“ firstInputField”,“ secondInputField”)...

CSRF:

CSRF代表跨站點請求偽造。

如今,服務器向CSRF令牌提供響應以避免CSRF安全攻擊非常普遍。 REST通過使用自動解析器並提供CSRF令牌來支持此功能。 

為了實現此REST,Assured需要提出額外的請求並解析網站(少量位置)。

我們可以通過編寫以下代碼來啟用CSRF支持:

給定().auth()。form(“ uName”,“ pwd”,formAuthConfig()。withAutoDetectionOfCsrf())。when()。get(“ URL”)。then()。statusCode(200);

另外,還可以幫助REST確保確保解析更加完美和健壯,我們可以提供CSRF字段名稱(此處假設我們使用的是Spring Security默認值,並且可以使用預定義的springSecurity FormAuthConfig):

給定().auth()。form(“ uName”,“ pwd”,springSecurity()。withCsrfFieldName(“ _ csrf”))。when()。get(“ URL”)。then()。statusCode(200);

默認情況下,CSRF值作為請求的形式參數傳遞,但如果需要,則我們可以配置將其作為標頭髮送,如下所示:

給定().auth()。form(“ uName”,“ pwd”,springSecurity()。withCsrfFieldName(“ _ csrf”)。sendCsrfTokenAsHeader())。when()。get(“ URL”)。then()。statusCode (200);

OAuth 1:

OAuth 1要求Scribe必須在類路徑中。 To use oAuth 1 authentication we can do:要使用oAuth XNUMX身份驗證,我們可以執行以下操作:

..

OAuth 2:

..

在上述方法中,將在標頭中考慮OAuth2 accessToken。 更明確地說,我們還可以執行以下操作:

..

在Request中傳遞File,字節數組,輸入流或文本:

當向服務器發送大量數據時,通常是使用多部分錶單數據技術的常用方法。 放心的提供了稱為multiPart的方法,該方法使我們可以指定文件,字節數組,輸入流或要上載的文本。 

給定().multiPart(新文件(“ /File_Path")).when().post("/upload”);

放心創建POST請求

通過POST和PUT請求,我們將數據發送到服務器及其基本上的資源創建/資源更新,您可以將其視為寫入或更新操作。

在POST請求中發送到服務器的數據在HTTP請求/ API調用的主體中發送。 

根據API的不同,要發送的內容或數據的類型可以具有不同的格式,即XML,JSON或其他一些格式由Content-Type標頭定義。 

如果POST主體由JSON數據組成,則標頭Content-Type將為application / json。類似地,對於由XML組成的POST請求,標頭Content-Type將為application / xml類型。

以下是相同的以下代碼段:

給定().contentType(“ application / json”)。param(“ pk”,“ pv”)。when()。body(“ JsonPAyloadString”)。post(“ url”)。then()。assertThat()。 statusCode(200);

注意:我們可以通過不同的方法來傳遞方法“ body”內的有效負載/請求主體,例如String(如上面的片段所示),JsonObject,作為文件等,

放心的PUT請求:

給定().contentType(“ application / json”)。param(“ pk”,“ pv”)。when()。body(“ JsonPAyloadString”)。put(“ url”)。then()。assertThat()。 statusCode(200);

使用Rest-Assured刪除請求:

給定().contentType(“ application / json”)。param(“ pk”,“ pv”)。when()。delete(“ url”)。then()。assertThat()。statusCode(200);

這樣我們就可以為不同的API動詞創建不同的Rest API調用(GET / POST / PUT / DELETE等)

Java中的序列化和反序列化:

序列化基本上是將對象狀態處理或轉換為字節流的過程。 另一方面,Java中的反序列化正在處理字節流或將字節流轉換為內存中的實際Java對象。 此機制用於對象的持久性。

下面是相同的框圖 

其餘API測試|| RestAssured快速指南2020教程

序列化的優點

答:保存/保留對象的狀態。

B.使對象流過網絡。

使用JAVA實現序列化

為了實現可序列化的Java對象,我們需要實現java.io.Serializable接口。

ObjectOutputStream類,其中包含負責序列化Object的writeObject()方法。

ObjectInputStream類還包含另一個稱為readObject()的方法,該方法負責反序列化對象。

實現java.io.Serializable接口的類,那裡的對像只能被序列化。

可序列化只是一個標記接口,與其他市場接口一樣,它沒有與之關聯的數據成員或方法。它用於“標記” java類,以便這些類的對象將具有某些功能。 像其他幾個標記器接口一樣:-可克隆和遠程等。

注意:

1.如果父類已經實現了Serializable接口,則不需要子類來實現相同的接口,反之亦然。

2.序列化過程僅存儲非靜態數據成員。

3.序列化不會存儲靜態數據成員和瞬態數據成員。因此,如果我們不需要存儲非靜態數據成員的值,則可以將其設為瞬態。

4.反序列化對象時,永遠不會調用構造函數。

步驟1:第一步基本上是創建一個實現Serializable接口的類:

導入java.io.Serializable;
公共類Dummy實現了Serializable {
    私人情報
    私有字符串數據;
    public Dummy(int i,字符串數據)
    {
        this.i = i;
        this.data =數據;
    }
}

步驟2:創建一個要序列化的類:

導入java.io.FileNotFoundException;
導入java.io.FileOutputStream;
import java.io.IOException;
導入java.io.ObjectOutputStream;
公共類序列化{
    公共靜態無效序列號(Object classObject,String fileName){
        嘗試{
            FileOutputStream fileStream =新的FileOutputStream(fileName);
            ObjectOutputStream objectStream =新的ObjectOutputStream(fileStream);
            objectStream.writeObject(classObject);
            objectStream.close();
            fileStream.close();
        } catch(FileNotFoundException e){
            // TODO自動生成的catch塊
            e.printStackTrace();
        } catch(IOException e){
            // TODO自動生成的catch塊
            e.printStackTrace();
        }
    }
    公共靜態void main(String [] args){
        Dummy dummyObj = new Dummy(10,“ Lambda-geeks”);
        序列化(dummyObj,“ DummSerialized”);
    }
}

步驟3:成功完成步驟2之後,您將看到創建的文件中包含一些數據,該數據基本上是Object成員的序列化數據。

  用Java反序列化:

這是下面的代碼片段:

 公共靜態對象DeSerialize(String fileName)
    {
        嘗試{
            FileInputStream fileStream = new FileInputStream(new File(fileName));
            ObjectInputStream objectStream = new ObjectInputStream(fileStream);
            對象deserializeObject = objectStream.readObject();
            objectStream.close();
            fileStream.close();
            返回deserializeObject;
        } catch(FileNotFoundException e){
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        } catch(ClassNotFoundException e){
            e.printStackTrace();
        }
        返回null;
    }

驅動程序代碼如下:

 公共靜態void main(String [] args){
      / * Dummy dummyObj = new Dummy(10,“ Lambda-geeks”);
        序列化(dummyObj,“ DummSerialized”);
        System.out.println(“ ------------------------------------------- -------------------------------“);
      */
        Dummy deSerializedRect =(Dummy)DeSerialize(“ DummSerialized”);
        System.out.println(“來自序列化對象的數據” + deSerializedRect.print());
        System.out.println(“ ------------------------------------------- -------------------------------“);
    }

JSONPATH更多語法/查詢:

讓我們假設一個JSON如下:

{
  “ OrganizationDetails”:“組織的虛擬詳細信息”,
  “地區”:“亞洲”,
  “ Emp-Details”:[
    {
      “ Org”:“ lambda-Geeks”,
      “信息”:{
        “電話”:1234567890,
        “添加”:“ XYZ”,
        “年齡”:45
      }
    },
    {
      “ Org”:“ lambda-Geeks-2”,
      “信息”:{
        “電話”:2134561230,
        “添加”:“ ABC”,
        “年齡”:35
      }
    }
  ]
}

在上述JSON中,OrganizationDetails&Region稱為Leaf節點,原因是它們沒有其他子節點/元素,但另一方面,Emp-Details具有子節點,因此不稱為Leaf節點。

在這裡,如果我們嘗試獲取OrganizationDetails的值,則需要使用:

$。組織詳細信息 
這將導致:
 [
  “組織的虛擬詳細信息”
]

像Wise一樣,我們需要編寫區域數據:

$。地區 

如果我們想找到第一位員工的年齡值,則可以這樣寫:

$ .Emp-Details [0] .Information.Age
這將導致:
[
  45
]

對於第二個員工的年齡,我們可以這樣寫

$ .Emp-Details [1] .Information.Age
這將導致:[35]

這樣,我們可以找出JsonPath表達式/查詢來獲取JSON中各個字段的數據。

關於德巴吉亞

其餘API測試|| RestAssured快速指南2020教程我本人是Debarghya Roy,我是一名工程架構師,與財富5強公司合作,並且是一名開源貢獻者,在各種技術堆棧中擁有大約12年的經驗/專業知識。
我曾經使用過各種技術,例如Java,C#,Python,Groovy,UI自動化(Selenium),移動自動化(Appium),API /後端自動化,性能工程(JMeter,Locust),安全自動化(MobSF,OwAsp,Kali Linux) ,Astra,ZAP等),RPA,流程工程自動化,大型機自動化,使用SpringBoot,Kafka,Redis,RabitMQ,ELK堆棧,GrayLog,Jen​​kins進行後端開發,還具有在雲技術,DevOps等方面的經驗。
我和我的妻子住在印度班加羅爾,對寫博客、音樂、彈吉他充滿熱情,我的人生哲學是全民教育,它催生了 LambdaGeeks。 讓我們通過鏈接連接 - https://www.linkedin.com/in/debarghya-roy/

en English
X