溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java的rest-assured怎么使用

發(fā)布時間:2021-12-30 15:02:56 來源:億速云 閱讀:122 作者:iii 欄目:云計(jì)算

本篇內(nèi)容主要講解“java的rest-assured怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“java的rest-assured怎么使用”吧!

 關(guān)于rest-assured
rest-assured 是一個能夠簡化測試rest服務(wù)的Java DSL,像ruby或者python一樣的動態(tài)語言去測試和驗(yàn)證http服務(wù)?;趈ava并且兼容了groovy動態(tài)語言的特性,使我們像寫腳本語言一樣去測試http服務(wù)。

例如:你的http服務(wù)( http://localhost:8080/lotto/{id})返回一個如下json:

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

很簡單的使用rest-assured斷言你的響應(yīng)結(jié)果是否符合預(yù)期。

get("/lotto").then().body("lotto.lottoId", equalTo(5));

或者你想斷言下 winnerId是不是 23 和 54:
get("/lotto").then().body("lotto.winners.winnerId", hasItems(23, 54));

如果看起來很簡單,have a try?

rest-assured小試牛刀
在我們沒有運(yùn)行測試用例之前,我們需要把**rest-assured**的maven依賴先引入

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

RestAssured這個類是整個測試框架的請求入口,類的內(nèi)部定義了一系列靜態(tài)方法,包括我們常用的POST, GET, PUT, DELETE, OPTIONS, PATCH and HEAD等請求類型,請求響應(yīng)結(jié)果
能用于我們常用的驗(yàn)證和斷言。

RestAssured.get方法請求http服務(wù)

Response response = RestAssured.get("http://localhost/greting?id=5");

請求響應(yīng)結(jié)果response中定義了一系列的json轉(zhuǎn)換方法,你可以很簡單把你的結(jié)果轉(zhuǎn)換成
json等字符串直接輸出

response.asString();

或者對應(yīng)實(shí)體bean轉(zhuǎn)換為json對象或者xml。

//json
GreetingBean as = response.as(GreetingBean.class);
//xml
XmlPath xmlPath = response.xmlPath();

也可以把返回結(jié)果進(jìn)行驗(yàn)證是不是你想要的結(jié)果

response.then().statusCode(200).body("name",equalTo("test"));

看到這里你可能認(rèn)為**rest-assured**提供的方法的確很簡單,但是我把httpclient或者
okhttp封裝一下,也可以達(dá)到這個效果,我是一個程序員,我就是喜歡重復(fù)造輪子,因?yàn)檫@樣才可以提高我自己的編程水平,那么OK,你一定要造一個比它還好用的輪子。
對于上面的http測試請求還是可以在簡化,能用小程序?qū)崿F(xiàn)的,決不用大程序。

第一步:

import static io.restassured.RestAssured.given;

第二步:

get("http://localhost/greting?id=5")

我們就可以使用簡單的get,post或者delete發(fā)送我們的請求,并且可以獲得響應(yīng)結(jié)果進(jìn)行斷言返回結(jié)果是否正確。
雖然我們在使用別人東西,但是我們也要知其然知其所以然,刨根問底。如果你足夠仔細(xì),打開源碼一識真面目,其實(shí)你會發(fā)現(xiàn)**rest-assured**本身也沒有什么神秘,他就是充分利用了java多態(tài)的特性,對接口進(jìn)行了高度的繼承和封裝。查看get或者post等一系列http請求方法的實(shí)現(xiàn),你會發(fā)現(xiàn)所有的請求體Request,rest-assured本身都對他進(jìn)行了重新定義,即RequestSpecification,這只是一個接口,它的實(shí)現(xiàn)類則是TestSpecificationImpl,這里面則是封裝了標(biāo)準(zhǔn)的http請求(如下,截取了其中的一部分,來自于類io.restassured.internal.TestSpecificationImpl),它是使用groovy語言進(jìn)行實(shí)現(xiàn)。


 /**
   * {@inheritDoc}
   */
  Response get(String path, Object... pathParams) {
    requestSpecification.get path, pathParams
  }

  /**
   * {@inheritDoc}
   */
  Response post(String path, Object... pathParams) {
    requestSpecification.post path, pathParams
  }

  /**
   * {@inheritDoc}
   */
  Response put(String path, Object... pathParams) {
    requestSpecification.put path, pathParams
  }

  /**
   * {@inheritDoc}
   */
  Response delete(String path, Object... pathParams) {
    requestSpecification.delete path, pathParams
  }

groovy是什么?Groovy是一種基于JVM(Java虛擬機(jī))的敏捷開發(fā)語言,它結(jié)合了Python、Ruby和Smalltalk的許多強(qiáng)大的特性,Groovy 代碼能夠與 Java 代碼很好地結(jié)合,也能用于擴(kuò)展現(xiàn)有代碼。

你可以再反過來看看返回結(jié)果response也是按照這種思路,里面也有一個實(shí)現(xiàn)類即ResponseSpecificationImpl。這里也就契合了為什么一開始我們?yōu)槭裁凑frest-assured是基于java DSL(*DSL是一種為了特定任務(wù)而設(shè)計(jì)的開發(fā)語言* )框架。

 rest-assured優(yōu)勢
* 足夠簡單,短,而且編寫測試用例快(*應(yīng)該是程序員為啥找不到女朋友的原因吧*)。
* 順序控制結(jié)構(gòu)(*最簡單的結(jié)構(gòu)莫過于此,執(zhí)行這條語句然后執(zhí)行下一條語句的形式*)
* 符合契約編程思想(*如果前置條件滿足的情況下調(diào)用函數(shù),那么函數(shù)的執(zhí)行將確立后置條件*)

rest-assured系統(tǒng)測試

耐心看了上面的內(nèi)容,相信你對這個測試框架有了個整體的了解,但是在現(xiàn)實(shí)場景中根本不可能使用java的main函數(shù)直接調(diào)用RestAssured里面的靜態(tài)函數(shù),因?yàn)檫@樣寫出來的測試用例是不容易維護(hù)的,也是不可移植的,因?yàn)檫@些測試用例今天你是簡單在打包前跑了下測試用例,確定沒有錯誤后,打成測試包,但是之后可能也對這個產(chǎn)品進(jìn)行持續(xù)集成(CI server或者jenkins等),又或者這個產(chǎn)品的用戶量比較大我們需要在Jmeter或者loaderunner中,跑下腳本,測試性能。這時我們要把*rest-assured*結(jié)合*Junit*(或者一些自己擅長的單元測試框架testNG等)進(jìn)行使用。

下面簡單介紹下幾種常見的測試用例場景:
第一步,確保你已經(jīng)引入Junit和rest-assured包。
并且在引入類的同時進(jìn)行靜態(tài)化,如下:

import static io.restassured.RestAssured.get;
import static io.restassured.RestAssured.given;
import static io.restassured.RestAssured.post;
import static org.hamcrest.Matchers.*;

@Before
public void setup() {
    RestAssured.baseURI = "http://localhost";
    RestAssured.port = 8080;
}

這里是使用Junit的注解,在運(yùn)行測試用例之前的準(zhǔn)備工作。這里我們配置了ip地址和端口??吹竭@里有的同學(xué)可能要問了我的請求是基于https單向請求,那么我們可以在setup函數(shù)中添加 :

`RestAssured.config.getSSLConfig().relaxedHTTPSValidation();`
這個設(shè)置代表信任所有客戶端,不用攜帶任何可信任證書,直接能夠請求到服務(wù)端,如果這時你使用OKHttp或者h(yuǎn)ttpURLConnection,你可能就要花時間自己實(shí)現(xiàn)繞過https認(rèn)證了,可能你現(xiàn)在手頭有一份可信任證書,想要模擬真是的瀏覽器環(huán)境,你可以這樣設(shè)置:

RestAssured.config.getSSLConfig().trustStore("test.truststore","123456");

我曾經(jīng)自己原生的java語言以及httpclient實(shí)現(xiàn)過基于證書的雙向認(rèn)證過程[具體請查看源碼](https://github.com/strictnerd/LearningSummary/tree/master/src/main/java/com/clq),已經(jīng)精簡到不能在精簡,還寫了個大概十行左右的代碼,如果不參考之前寫的,我可能還要翻開API看看到底是怎么調(diào)用的。但是rest-assured就跟我們做了很好的封裝如下:

RestAssured.certificate("clq.truststore", "123456","clq.p12", "123456", CertificateAuthSettings.certAuthSettings().keyStoreType("PKCS12").trustStoreType("jks"));

因?yàn)榇a的封裝不夠好,降低了我們的工作效率,很明顯rest-assured提高了我們的工作效率,降低了我們在工作中可能出錯的機(jī)率。
其實(shí)它這里面不僅做了單雙向認(rèn)證的封裝,我們平時常見的用戶名密碼登錄、oauth認(rèn)證、代理請求等等。

第二步,開始我們的rest服務(wù)測試

get請求測試


@Test
public void greetingTest() {
    given().param("name", "clq")
            .then().statusCode(200)
            .body("id", equalTo(2),"content", containsString("Hello"))
    .when().get("/greeting");
}

這一大串的順序控制結(jié)構(gòu)代碼的含義就是,給出參數(shù)name,當(dāng)我發(fā)送get請求之后,那么你給我返回響應(yīng)碼200,并且id=2,content為hello。
如果你的這個rest服務(wù)請求測試有一定的特殊性,那么你可以在這個測試用例中進(jìn)行另外的聲明。如下:


@Test
public void greetingTest() {
    try {
        RestAssured.requestSpecification = new RequestSpecBuilder().addCookie("cookie","123456").build();
        given().param("name", "clq")
                .then().statusCode(200)
                .body("id", equalTo(2),"content", containsString("Hello"))
        .when().get("/greeting");
    }finally {
        RestAssured.reset();
    }
    
}

使用完之后,記得在finally里面進(jìn)行reset,因?yàn)橛锌赡軙绊懫渌臏y試用例。同樣的我們舉一個基于json請求的post實(shí)例,(這個框架可不僅支持基于json格式body傳參,也支持我們常用的form表單或者xml傳參。)


@Test
public void postTest() {
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("id", 123412);
    map.put("addr", "zz");
    map.put("age", Arrays.asList(12,27,23,41));
    given().contentType(ContentType.JSON)
            .body(JSON.toJSONString(map)).proxy(ProxySpecification.host("192.168.1.11").withPort(2010))
            .then().statusCode(200)
            .body("addr", equalTo("zz"), "id", equalTo(123412), "age[1]", is(27))
            .time(lessThan(1L),TimeUnit.SECONDS)
    .when().post("/welcome");
}


這個post請求,我在這里設(shè)置了特別多的場景,首先是requestBody里面的json傳參,并且使用代理192.168.1.11:2010,當(dāng)我發(fā)送post請求后,那么給我返回響應(yīng)碼200,body里面的結(jié)果符合預(yù)期(里面內(nèi)置了hamcrest這個包,它的主要作用是response返回結(jié)果進(jìn)行驗(yàn)證)。這些場景也是比較常見的,比如說,我的后臺要添加一個這樣的功能,支持微信公眾號服務(wù)的調(diào)用,但是我的整個后臺服務(wù)都是部署在內(nèi)網(wǎng),只有微信調(diào)用微信公眾號獲取openid的這一部分需要使用外網(wǎng),于是搭建了一個外網(wǎng)的代理服務(wù)器,那么我就可以基于http請求的代理服務(wù),只讓這部分rest服務(wù)訪問外網(wǎng)。

我們現(xiàn)實(shí)場景中還有一些經(jīng)常使用的像文件上傳和下載之類的,它也是支持的。

文件上傳,并且在上傳文件的同事支持參數(shù)的傳遞。

@Test
public void uploadFile() {
    Response post = given().param("id", "123456")
            .multiPart("file", new File("D:/zzrd.jpg"))
            .post("/file");
    Assert.assertEquals("123456", post.asString());
}

文件下載如下:

@Test
public void downloadFile() {
    Response response = given().get("/export");
    byte[] bytes = response.asByteArray();
    BufferedOutputStream bos = null;
    try {
        bos = new BufferedOutputStream(new FileOutputStream(new File("d:/xxoo.xls")));
        bos.write(bytes);
    } catch (FileNotFoundException e) {
        //TODO
        e.printStackTrace();
    } catch (IOException e) {
        //TODO
        e.printStackTrace();
    }finally {
        try {
            if(bos != null) {
                bos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


 rest-assured使用場景
我的系統(tǒng)測試非常復(fù)雜,有基于表單的,基于json數(shù)據(jù)格式的,還有使用了xml格式,有部分返回的數(shù)據(jù)結(jié)構(gòu)也很復(fù)雜,有的接口請求地址或者端口是不一樣的,或者使用了代理等功能。

你可以直接使用rest-assured來解決你碰到的這些實(shí)際問題。

我是不是可以在業(yè)務(wù)代碼的請求中直接使用rest-assured?

其實(shí)這個我是不推薦的,因?yàn)槲以?jīng)在我機(jī)器上,基于我自己的系統(tǒng)對rest-assured和httpclient做了比較,分別單線程測試(*分別請求1000次,rest-assured耗時85s,httpclient耗時79s*)后來我自己也做過多線程測試,無論怎么測試,得出的結(jié)論就是httpclient也比rest-assured快。當(dāng)然這個可能也不一定準(zhǔn)確,服務(wù)不同環(huán)境不同,測試結(jié)果也會隨之改變。畢竟rest-assured底層對httpclient又進(jìn)行了一次封裝,而且使用了groovy,groovy雖然是一門動態(tài)語言,但是他還是基于jvm平臺的,最后還是編譯成了class。個人認(rèn)為,groovy除了在jvm平臺上執(zhí)行,并且寫的腳本足夠短之外,跟其它的ruby或者python等腳本語言相比,是沒有什么優(yōu)勢的。但是他作為測試用例來用,優(yōu)勢還是非常大的,因?yàn)闇y試用例,不是線上環(huán)境,對性能沒什么特別要求。

 我使用了springmvc Controller可以使用rest-assured做接口測試嗎?

其實(shí)對于這個rest-assured也有對應(yīng)的spring-mock-mvc,但是spring官方也有基于spring-test接口測試,要是還用rest-assured提供的,老感覺有一種拿著錘子找釘?shù)母杏X。

測試帶給我們的好處
測試給我們的產(chǎn)品帶來的好處是非常多的,這里我們只是基于rest API進(jìn)行測試,在單元測試中來說,這是一個粗粒度的測試,如果想更加詳細(xì),像基于h3數(shù)據(jù)庫的腳本測試,但是現(xiàn)在我們大部分框架都使用了jpa,這個測試能給我們帶來一定好處,但是工作量也是很可觀的,該不該進(jìn)行一些基于h3內(nèi)存數(shù)據(jù)庫的模擬測試,這里我們自己拿捏,不做過多的建議。至于基于mock業(yè)務(wù)邏輯的隔離測試,當(dāng)我們碰到復(fù)雜業(yè)務(wù)邏輯,或者在某種環(huán)境下,某個場景難于模擬,如果我們使用了mock,這種場景完全可以避免掉。這種測試該做還是要做的,下面我們可以簡單說下單元測試本身給我們帶來哪些明面上的好處。

 首先應(yīng)該就是它是一種驗(yàn)證行為,而且具有一定的可回歸性。

我們只是在每完成一個功能之后寫了一個測試用例,立刻可以驗(yàn)證我們的功能是通過的。當(dāng)我們的一個模塊或者一個大的功能通過之后,我們可以基于maven快速的運(yùn)行所有的單元測試。來保證我們的功能在本地是通過測試的。其實(shí)就是在開發(fā)后期,我們看著某一塊功能或者業(yè)務(wù)邏輯很不爽(這是別人寫的),那么我們就可以直接修改功能或者重構(gòu),之后我們就可以利用測試用例來保證沒有破壞其他的設(shè)計(jì),說白了單元測試能給我們改善設(shè)計(jì)帶來信心。

單元測試代碼更具有可維護(hù)性,在某種程度上,可以認(rèn)為是一種文檔的行為,但是帶來效果可能比文檔還要好。

一套系統(tǒng),我開發(fā)出來,可能過幾天交給AA了,2年后交給了CC,CC怎么才知道后臺服務(wù)系統(tǒng)是完全沒有問題的,或者說他怎么知道某個rest服務(wù)的目的是什么。如果說我們測試用例中寫了完整的輸入和輸出的斷言機(jī)制,整體系統(tǒng)的代碼可讀性都會增強(qiáng)。

 能夠在某種程度上提升代碼質(zhì)量。

這一點(diǎn)我也認(rèn)為是非常重要的,當(dāng)你編寫完一個簡單的功能時,你運(yùn)行一下,輸入一些邊界條件,保證程序是可運(yùn)行的。這一點(diǎn)是必須的,但是當(dāng)你出現(xiàn)問題,通常我們調(diào)試代碼的過程都是打個斷點(diǎn),進(jìn)入代碼內(nèi)部進(jìn)行詳細(xì)分析,這時你對你的剛剛完成的業(yè)務(wù)邏輯有個整體的認(rèn)識,這時如果你發(fā)現(xiàn)有不合適的地方,或者代碼冗余的地方,你應(yīng)該開始調(diào)整了。特別是當(dāng)你使用mock進(jìn)行隔離測試時,有時為了測試某一個場景,你不得不解耦合(因?yàn)檫@樣讓你更容易測試),在不知不覺中提升了自己的代碼質(zhì)量。

當(dāng)然上述都是一些單元測試的好處,測試本來都應(yīng)該是軟件開發(fā)的一部分,這些都是不可否認(rèn)的。甚至有人提出了TDD,先編寫測試用例,測試用例來確定要編寫什么產(chǎn)品代碼,這些都充分說明了單元測試的重要性。

所以我們不僅要寫測試用例,還要寫好測試用例。

系統(tǒng)測試覆蓋率依然少的可憐?

其實(shí)究其原因無非就是產(chǎn)品更新迭代快需要快速占領(lǐng)市場,或者項(xiàng)目趕得實(shí)在太緊急,根本沒有時間寫測試用例,這里一般都是說沒有時間寫測試用例,但是還是要測試的。我感覺除了一些業(yè)界大牛外,在自己的一段業(yè)務(wù)代碼沒有做測試前,誰敢保證完全沒有任何問題。再說業(yè)界大牛估計(jì)寫業(yè)務(wù)代碼的也不多吧。所以我經(jīng)常就發(fā)現(xiàn)一些現(xiàn)象就是,大部分人在這種情況下,對于rest服務(wù)接口,直接簡單省事的用一個httpURLconnection輪番測試所有的接口,最后測著測著自己的測試代碼都有問題了,這還如何保證自己服務(wù)端代碼的質(zhì)量呢?有的同學(xué)可能比較擅長使用一些工具,像谷歌的postman或restclient等http接口測試工具,直接把請求拷貝過去,參數(shù)添加上去,運(yùn)行下,OK!有些運(yùn)用熟練地同學(xué)發(fā)現(xiàn)里面還可以收藏,把你以前添加的接口收藏到一個列表中,以后可以繼續(xù)使用。在某種程度上來說,他提高了我們一些效率,但是難道我們每次上線前都得手動把你之前添加的接口,挨個點(diǎn)一遍么,剛開始看著還能說過去,但是長遠(yuǎn)看,效率太低。

這里我們在反過來看rest-assured,或者我們開發(fā)出一套適用于我們系統(tǒng)的測試框架,通常都是一句邏輯控制代碼加斷言,這樣一句簡單的代碼,的確能夠保證我們的產(chǎn)品質(zhì)量,還能提升我們的工作效率。

到此,相信大家對“java的rest-assured怎么使用”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI