一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一


一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一


1 . 初識 REST Assured

在 REST Assured 的官方 GitHub 上有這樣一句簡短的描述: Java DSL for easy testing of REST services 簡約的 REST 服務測試 Java DSL

1.1 優點:

REST Assured 官方的 README 第一句話對進行了一個優點的概述,總的意思表達的就是簡單好用。那麼 REST Assured 有哪些優點,又該如何使用呢?

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一

用 Java 做接口自動化測試首選 REST Assured,具體原因如下:

  • 開源
  • 簡約的接口測試 DSL
  • 支持 xmljson 的結構化解析
  • 支持 xpathjsonpathgpath 等多種解析方式
  • 對 spring 的支持比較全面

功能很齊全,部分我自己也還沒有具體用到,瞭解到了方向,需要時隨時查找學習


2. 如何使用


添加 maven 依賴

<code><dependency>
<groupid>io.rest-assured/<groupid>
<artifactid>rest-assured/<artifactid>
<version>4.0.0/<version>
<scope>test/<scope>
/<dependency>/<code>

2.1 基本三步曲

我們對接口進行測試一般由三步曲:傳參、發請求、響應結果斷言,REST Assured給我們提供了清晰的三步曲,以given、when、then的結構來實現,基本寫法如下:

<code>//使用參數
given().
param("key1", "value1").
param("key2", "value2").
when().
post("/somewhere").
then().
body(containsString("OK"))

//使用X-Path (XML only)
given().
params("firstName", "John", "lastName", "Doe").
when().
post("/greetMe").
then().
body(hasXPath("/greeting/firstName[text()='John']"))/<code>

2.2 分步拆解

前提:現有一個post請求的登錄接口。

請求體body如下

<code>{
"password": "elcrD28ZSLLtR0VLs/jERA\\\\u003d\\\\u003d\\n",
"grant_type": "password",
"scope": "server",
"userType": 1,
"username": "xxx"
}/<code>

Request Header 如下:

<code>Headers:    Authorization=Basic c3lzdGVtxxxRlbQ==
Host=47.103.xxx.133
Accept=*/*
Content-Type=application/json; charset=ISO-8859-1/<code>


分步拆解一Givern


我們發送請求經常需要帶有參數,使用 given() 就可以實現,當時當我們使用 given() 的時候發現其中有很多傳參方法如下:


一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一

沒錯,在傳參的方法中包含了 param、pathParam、queryParam 和 formParam,下面來研究下這幾個傳參方法的區別


  • param
    通常我們都會使用 given().param 方法來傳參,REST Assured 會根據 HTTP 方法自動嘗試確定哪種參數類型(即查詢或表單參數),如果是 GET,則查詢參數將自動使用,如果使用 POST,則將使用表單參數;


  • queryParam 和 formParam
    有時候在 PUT 或 POST 請求中,需要區分查詢參數和表單參數時,就需要使用queryParam 和 formParam 方法了,具體寫法如下:
<code>given().
formParam("formParamName", "value1").
queryParam("queryParamName", "value2").
when().
post("/something")/<code>
  • pathParam

使用given時指定請求路徑的參數,這個方法很少用到,或者說我本人幾乎沒用到過(可能我的修行還不夠,踩坑還太少~);具體寫法如下:

<code>given().
pathParam("OAuth", "oauth").
pathParam("accessToken", "token").
when().
post("/auth/{OAuth}/{accessToken}").
then().
../<code>
  • header/headers

經常還需要在請求頭中帶入參數,這個時候就可以使用header或headers方法,寫法如下:

<code>given()
.header("Authorization","Basic c3lzdGVtOxxxbQ==")
.header("Host","47.xxx.xxx.133")/<code>
  • 或者用headers將多個參數寫在一起:
<code>given()
.headers("Authorization","Basic c3lzdGVtxxx3RlbQ==","Host","47.xxx.xxx.133")/<code>
  • cookie

有時候需要在請求中帶入cookie,restassured提供了cookie方法來實現:

<code>given()
.cookie("c_a","aaaaaa")
.cookie("c_b","bbbbbb"). ../<code>
  • contentType

經常還會設置contentType,最常見的就是application/json了,寫法如下:

<code>given().contentType("application/json"). ..
//或者
given().contentType(ContentType.JSON). ../<code>
  • body

在POST, PUT 或 DELETE請求中,我們經常還需要帶上請求體body,寫法如下:

<code>given().body("{\\n" +
"\\t\"password\": \"elcrD28xxxR0VLs/jERA\\\\\\u003d\\\\\\u003d\\\\n\",\\n" +
"\\t\"grant_type\": \"password\",\\n" +
"\\t\"scope\": \"server\",\\n" +
"\\t\"userType\": 1,\\n" +
"\\t\"username\": \"xxx\"\\n" +
"}")/<code>

也可以用request更為明確的指出是請求body:

<code>given().request().body("{\\n" +
"\\t\"password\": \"elcrD28xxxR0VLs/jERA\\\\\\u003d\\\\\\u003d\\\\n\",\\n" +
"\\t\"grant_type\": \"password\",\\n" +
"\\t\"scope\": \"server\",\\n" +
"\\t\"userType\": 1,\\n" +
"\\t\"username\": \"xxx\"\\n" +
"}")/<code>
  • 沒有參數

如果我們沒有參數需要傳遞,也可以省略掉given():

<code>get("/lotto").then().assertThat().body("lotto.lottoId", equalTo(5));/<code>

實際運行結果:

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一


分步拆解二When


  • when主要用來觸發請求,在when後面接著請求URL:
<code>given().when().post("http://47.103.xxx.133/auth/oauth/token"). ../<code>

前面在 given 中我們設置了很多請求參數,在 when 中也可以設置,只不過要注意的是在請求之前設置;這也比較好理解,如果再請求之後的話,參數都設置怎麼發請求呢?

<code> given()
.when()
.contentType(ContentType.JSON)
.headers("Authorization","Basic c3lzxxx3RlbQ==","Host","47.xxx.xxx.133")
.request().body("{\\n" +
"\\t\"password\": \"elcrD28ZSLLtR0VLs/jERA\\\\\\u003d\\\\\\u003d\\\\n\",\\n" +
"\\t\"grant_type\": \"password\",\\n" +
"\\t\"scope\": \"server\",\\n" +
"\\t\"userType\": 1,\\n" +
"\\t\"username\": \"qinzhen\"\\n" +
"}")
.post("http://47.xxx.xxx.133/auth/oauth/token")
. ../<code>

分步拆解三Then


then後面可以跟斷言,也可以獲取響應值


  • 斷言-then().body()
    then().body() 可以對響應結果進行斷言,在 body 中寫入斷言:
<code>.. post("http://47.xxx.xxx.133/auth/oauth/token")
.then().statusCode(200).body("code",equalTo(1));/<code>

其中statusCode(200)是對狀態碼的斷言,判斷狀態碼是否為200; body("code",equalTo(1))是對返回體中的 code 進行斷言,要求返回 code值為1 。


注:這裡的equalTo使用的是hamcrest斷言,不瞭解的小夥伴可參考另外一篇文章:Junit原生斷言和hamcrest斷言的區別及使用


實操演示:我們將上述的 given、when、then 結合起來看一下實際運行效果,這裡在運行之前再提一個功能,我們可以在 when 和 then 後面加上.log().all(),這樣在運行過程中就可以把請求和響應的信息都打印出來:

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一


  • 獲取響應-then().extract().body().path("code")
    我們可以在 then 後面利用 .extract().body() 來獲取我們想要 body 的返回值,它們也可以直接接在斷言後面,寫法如下:
    注意這裡的body() 不要和請求體body()以及斷言的body()混淆了
<code>.. .then()
.log().all().statusCode(200).body("code",equalTo(1))
.extract().body().path("code");/<code>

實操演示:

演示前再來看一個新的功能,上面我們再寫請求體 body 時時這樣的:

<code>body("{\\n" +
"\\t\"password\": \"elcrD28ZxxxVLs/jERA\\\\\\u003d\\\\\\u003d\\\\n\",\\n" +
"\\t\"grant_type\": \"password\",\\n" +
"\\t\"scope\": \"server\",\\n" +
"\\t\"userType\": 1,\\n" +
"\\t\"username\": \"qinzhen\"\\n" +
"}")/<code>

看起來有點醜,改造一下;rest-assured 為我們提供了一個利用 HashMap 來創建json 文件的方法,先把要傳的字段放入 hashmap 中,然後用 contentType 指明JSON 就可以了,具體寫法如下:

<code>HashMap map = new HashMap();
map.put("password","elcrD28ZSLLtR0VLs/jERA\\\\u003d\\\\u003d\\n");

map.put("grant_type","password");
map.put("scope","server");
map.put("userType",1);
map.put("username","xxx");
given()
.headers("Authorization","Basic c3lzdGVtxxxlbQ==","Host","47.xxx.xxx.133")
.contentType(JSON)
.body(map). ../<code>

現在進行完整的請求,獲取返回值 code 並打印:

<code>HashMap map = new HashMap();
map.put("password","elcrD28ZSLLtR0VLs/jERA\\\\u003d\\\\u003d\\n");
map.put("grant_type","password");
map.put("scope","server");
map.put("userType",1);
map.put("username","xxx");
Integer code =
given()
.headers("Authorization","Basic c3lzdGVtxxxlbQ==","Host","47.xxx.xxx.133")
.contentType(JSON)
.body(map).
when()
.log().all().post("http://47.xxx.xxx.133/auth/oauth/token").
then()
.log().all().statusCode(200).body("code",equalTo(1))
.extract().body().path("code");
System.out.println("返回code的值是:"+code);/<code>

運行結果:

一個自動化測試方案讓我搞定軟件測試面試:REST Assured 實踐 一

寫在最後

關於REST Assured,這裡僅僅算是初步認識。認識它的語法結構和功能,對於更多豐富的用法還需要慢慢探索研究,特別是斷言的部分,是測試工程師最常用最終要的功能之一。


分享到:


相關文章: