接口測試“八重天”---RestAssured

要記住每一個對你好的人,因爲他們本可以不那麼做。

              ---久節奏,慢讀書

 

一、什麼是RestAssured

偶然在逛帖子的時候發現一個接口測試框架,覺得不錯,學習學習。

官方地址:http://rest-assured.io/

那麼瞧瞧官方是怎麼說的:

Testing and validating REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into the Java domain.

與動態語言(如Ruby或Groovy)相比,用java測試和驗證REST服務要困難的多。RestAssured將使用這些語言的簡單性帶入java域。

可能前面也有記錄過HttpClient相關的帖子,但是個人覺得RestAssured更爲簡單、便捷、易讀!

二、RestAssured常規用法

官方文檔:https://github.com/rest-assured/rest-assured/wiki/Usage

Maven依賴:

<dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>3.0.6</version>
            <scope>test</scope>
</dependency>

其他的如jsonPath,xmlPath,Spring的依賴去上方地址去查找。

1、簡單的get無參請求

先仿照官方文檔搞個demo。

import org.junit.Test;

import static io.restassured.RestAssured.*;
import static io.restassured.matcher.ResponseAwareMatcher.*;
import static org.hamcrest.Matcher.*;

public class Baidu {
    @Test
    public void testGetHtml(){
        given()
                .log().all().get("https://www.baidu.com")
        .then()
          .log().all().statusCode(
200); } }

看一下輸入內容

 

百度的html文檔。

那麼解析一下代碼。

given()表示開頭輸入數據。

.log()表示打印日誌。

.all()表示打印所有的日誌。

.get(https://www.baidu.com)表示get請求該域名(post請求方式:.post())。

.then()表示對結果進行斷言。

.statusCode()表示對狀態碼進行斷言。

其實是等價於:curl -L https://www.baidu.com

ps:此處有個細節內容

  import static xx.xxx.*;

  導入該類的靜態方法;也可只導入某個靜態方法;在測試類中,可直接用方法名調用靜態方法,而不必用ClassName.方法名的方式。

  例如:可以將System.out.printIn();寫成靜態方法print(),在使用的時候直接print()即可。

  上述測試方法中的given()、.then()。

2、傳參get請求

上例中並沒有傳入參數,那再上一個傳入參數的demo。

 

import org.junit.Test;

import static io.restassured.RestAssured.*;

public class LocalInterface {
    @Test
    public void testlocal(){
        given()
                .queryParam("username","Richered")
        .when()
                .get("http://localhost:8000/CGIProject/cgi-bin/")
        .then()
                .statusCode(200);
    }
}

 

此處請求本地啓動的cgi服務接口。

可以看到,.queryParam()傳入參數username=Richered。

.get()請求接口http://localhost:8000/CGIProject/cgi-bin/

請求成功。

查看服務端接收到的請求。

 可以看到是標準的http請求。

3、http頭信息處理方法

那麼我們在日常的工作中難免會自定義請求頭信息,最常見的是自定義Cookie。

請求頭如何去構造。

given()
                .queryParam("username","Richered")
                .header("Cookie","Custom Cookie")

提供方法.header()即可搞定。

4、form表單傳參

 

given()
                .header("Cookie","Custom Cookie")
                .formParam("username","Richered")

 

方法.formParam()

5、https請求

useRelaxedHTTPSValidation();

 

 該方法表示信任證書

6、向代理服務器發送請求

proxy("127.0.0.1",8000);

7、發送請求數據爲json報文

ps:json、xml類的報文需要引入其提供的依賴.

 

<dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>json-schema-validator</artifactId>
      <version>4.1.2</version>
      <scope>test</scope>
</dependency>

 

demo:

 @Test
    public void testPostJson(){
        HashMap<String , Object> map = new HashMap<String ,Object>();
        map.put("username","admin");
        map.put("password","admin");
        map.put("capcha","n6d58");

        given().log().all()
                .contentType(ContentType.JSON)
                .body(map)

        .when()
                .post("http://localhost:8080/renren-fast/sys/login")

        .then()
                .statusCode(200);
    }

可以看到發送json報文的方式是使用HashMap的方式進行組合json格式。

ps:需要指定請求報文的類型:contentType(ContentType.JSON)

 

那麼其他報文類型也是一樣的

8、斷言

斷言絕對是重中之重。上方的demo中有提到斷言,.statusCode()【斷言其狀態碼】,當然我們斷言僅僅憑狀態碼是不夠的。

RestAssured支持jsonpath、xpath語法、Groovy語法斷言。

其斷言方式大概有這麼幾種:

1、標誌性斷言:assertXXX:assertEqual

2、Hamcrest斷言assertThat:assertThat(x, is(3))

3、RestAssured斷言:then().xx

4、body斷言:Xmlpath、jsonpath等

這裏就直接使用官方demo來寫例子。

ps:官方的json報文還是和前面Jmeter斷言那一篇的報文例子一樣。

jsonpath、xpath語法在這兒就不提了,都是基本功,一些基本用法可以翻翻前面的內容。

demo響應報文內容:

{  
   "store":{  
      "book":[  
         {  
            "author":"Nigel Rees",
            "category":"reference",
            "price":8.95,
            "title":"Sayings of the Century"
         },
         {  
            "author":"Evelyn Waugh",
            "category":"fiction",
            "price":12.99,
            "title":"Sword of Honour"
         },
         {  
            "author":"Herman Melville",
            "category":"fiction",
            "isbn":"0-553-21311-3",
            "price":8.99,
            "title":"Moby Dick"
         },
         {  
            "author":"J. R. R. Tolkien",
            "category":"fiction",
            "isbn":"0-395-19395-8",
            "price":22.99,
            "title":"The Lord of the Rings"
         }
      ]
   }
}

官方demo:斷言該報文中價格低於10的書籍title爲:Moby Dick和Sayings of the Century

@Test
    public void TestAssertion(){
        given()
                .contentType(ContentType.JSON)
        .when()
                .get("http://localhost:8000/CGIProject/cgi-bin/store.json")
        .then()
                .log().all()
                .body("store.book.findAll { it.price < 10 }.title",hasItems("Sayings of the Century", "Moby Dick"));
    }

使用閉包查找價格低於10的所有書籍,返回書籍的title,再使用hasItems匹配斷言標題。

findAll關鍵字、hasItems()方法

再做一個錯誤的斷言例子,斷言一下價格低於5的書籍是否爲Sayings of the Century和 Moby Dick(修改上方表達式中的價格即可),查看一下報錯、

 

 

 其斷言失敗的原因很清楚,無與表達式相匹配的結果;表達式內容。

官方提供了更爲複雜的demo2:

要求:斷言所有作者姓名長度之和大於50.

展示Groovy強大的時候來了。

看看其處理方式,簡單又易懂。

 

then().
       body("store.book.author.collect { it.length() }.sum()", greaterThan(50));

 

store.book.author:得到所有的作者

使用閉包{it.lenth()},調用結果列表中的collect方法,其作用爲:對每個作者使用length()方法。

在列表中只需要使用.sum()方法對所有長度進行求和。最終結果爲53,大於50.

ps:groovy使用*爲列表每個元素調用函數的方法非常方便:

  def words = ['ant','buffalo','cat','dinosaur']

  assert[3,6,3,8] ==words*.length()

詳情請去官方文檔中查看。

使用jsonpath的方式也一併貼上來:

int sumOfAllAuthorLengths = from(response).getInt("store.book.author*.length().sum()");
assertThat(sumOfAllAuthorLengths, is(53));

 還有一個需要注意的地方,斷言內容爲float和double類型的數據,需要加f和d

9、官方推薦書寫格式

 

given()
        .xxxxx
.when()
        .xxxxx
.then()
        .xxxxx

 

10、獲取響應數據

在上方的例子中,爲了方便查看請求過程,使用了.log().all()的方法。

那麼獲取響應數據:

 InputStream stream = get("http://localhost:8000/CGIProject/cgi-bin/store.json").asInputStream();
byte[] byteArray = get("http://localhost:8000/CGIProject/cgi-bin/store.json").asByteArray(); String json = get("http://localhost:8000/CGIProject/cgi-bin/store.json").asString();

11、上下文關聯

在常見的業務邏輯中,會有這麼一種業務邏輯。

例如:先登錄-->購買商品

購買商品必須先登錄成功,那麼開發的實現方式均不一致。

有可能是登錄成功之後響應報文中傳給客戶端一些參數,繼續請求;有可能是登錄成功將校驗成功的令牌存入cookie中,當然還有更爲複雜的,此處只是舉例。

針對這種業務邏輯RestAssured中如何處理

響應報文demo:

{
     "title" : "My Title",
      "_links": {
              "self": { "href": "/title" },
              "next": { "href": "/title?page=2" }
           }
 }
@Test
    public void Relation(){
        String nextTitleLink = given().
                                    param("param_name","param_value").
                                when().
                                    get("http://localhost:8000/CGIProject/cgi-bin/MyTitle.json").
                                then().
                                    contentType(ContentType.JSON).
                                    body("title", equalTo("My Title")).
                                extract().
                                    path("_links.next.href");
        System.out.println(nextTitleLink);

        given().log().all()
                .get("http://localhost:8000/CGIProject/cgi-bin/MyTitle.json" + nextTitleLink);

    }

extract().path("jsonpath表達式")

該例既請求校驗了接口,也拿到了自己需要的參數數據;

那如果需要從響應報文中取到多個參數呢?官方也給出瞭解釋

 

@Test
    public void Relation1(){
        Response response = given().
                                    param("param_name","param_value").
                                 when().
                                    get("http://localhost:8000/CGIProject/cgi-bin/MyTitle.json").
                                 then().
                                    contentType(ContentType.JSON).
                                    body("title", equalTo("My Title")).
                                  extract().
                                    response();
        String nextTitleLink = response.path("_links.next.href");
        String headerValue = response.header("headerName");
    }

 

ok、本篇先記錄學習這些,後續補充

 

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