就是這麼簡單!使用Rest-assured 測試Restful Web Services
使用 Rest-assured 測試 Restful Web Services
這裡向大家介紹一個測試Restful web service 的框架,叫Rest-assured.
他提供了一系列好的功能,像DSL式的語法, XPath-Validate, 檔案上傳,Specification重用, 使用代理, Spring MVC mock module測試Controllers等等,讓你在Java裡面測試Rest service 和那些動態語言Ruby, Groovy一樣靈活。
目錄 1. 前提 2. 配置 3. Example詳解 4. Troubleshooting 5. 參考來源
前提條件
- JDK >= 1.6
- Maven 3
配置Maven工程pom檔案如下
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
Example
a) 測試一個GET 請求方法,
請求URL : http://10.46.28.193:8080/service/v1/user/login
返回JSON內容如下
{ "userInfo": { "password": null, "userId": "wadexu", "accessSecurityCodes": "10000000000000000000", "firstName": "Wade", "lastName": "Xu", "status": 8, "officePhone": "58730", "email": "[email protected]", "homePhone": "123" }, "success": true, "error": null }
測試程式碼如下:
@Before public void setUp() { RestAssured.baseURI= "http://10.46.28.193"; RestAssured.port = 8080; RestAssured.basePath = "/service/v1"; } @Test public void testUserLogin() { expect(). statusCode(200). body( "success", equalTo(true), "userInfo.userId", equalTo("wadexu"), "userInfo.firstName", equalTo("Wade"), "userInfo.lastName", equalTo("Xu"), "error", equalTo(null)). when(). get("/user/login?userName=wadexu&password=NzrmRcIfIW4="); }
注意我這裡請求時的引數直接塞進了URL裡, 稍後會講到如何指明引數。
b) 如何使用JSON path
還是同上面的例子, 測試程式碼如下:
@Test public void testUserLogin_JsonPath() { Response response = get("/user/login?userName=wadexu&password=NzrmRcIfIW4="); assertEquals(200, response.getStatusCode()); String json = response.asString(); JsonPath jp = new JsonPath(json); assertEquals("wadexu", jp.get("userInfo.userId")); assertEquals("Wade", jp.get("userInfo.firstName")); assertEquals("Xu", jp.get("userInfo.lastName")); assertEquals("123", jp.get("userInfo.homePhone")); }
c) 如何使用引數
Get請求是用queryParam, 如果你直接寫 param,在這個case裡也可以,Rest Assured 會自動判斷引數型別(query or form parameter), 在有些case裡, Put 或 Post 你得指明引數型別
@Test public void testUserLogin_Parameter() { final String userName = "wadexu"; final String password = "NzrmRcIfIW4="; given(). queryParam("userName", userName).queryParam("password", password). expect(). statusCode(200). body("success", equalTo(true), "userInfo.userId", equalTo("wadexu"), "userInfo.firstName", equalTo("Wade"), "userInfo.lastName", equalTo("Xu"), "error", equalTo(null)).when() .get("/user/login"); }
另外,有些Post 請求URL後面是有引數的, 這時候 你可以這樣寫
post("/reserve/{hotelId}/{roomNumber}", "My Hotel", 23);
或者
given(). pathParam("hotelId", "My Hotel"). pathParam("roomNumber", 23). when(). post("/reserve/{hotelId}/{roomNumber}"). then(). ..
d) 再來看一個POST 請求, 這時候需要請求訊息體body了,request body是JSON體如下:
{
"customerId": "CDICC",
"broker": "test",
"editUserId": "wadexu"
}
測試程式碼:
@Test public void testCreate() { final String bodyString = "{\"customerId\": \"CDICC\",\"broker\": \"test\",\"editUserId\": \"wadexu\"}"; given(). contentType("application/json"). request().body(bodyString). expect(). statusCode(200). body( "order.orderNumber", is(Number.class), "order.deleteDate", is(nullValue()), "success", equalTo(true)). when(). post("/order"); }
這時除了用到request().body
還多加了一個header 請求訊息頭 -- ContentType
set Headers 的方法有很多, 上面是其一, 你還可以按如下方式做:
given().header("Content-Type", "application/json") given().headers("Accept", "application/json", "Content-Type", "application/json")
另外 注意到期望結果的比較沒有, 這裡用到org.hamcrest.Matchers的一些方法, 因為Order number 每次不一樣,無法判斷具體是多少,所以就看是否是數字就行了,刪除日期是null value
hamcrest.Matchers 裡的各種匹配器有興趣的童鞋可以研究下, 對測試斷言很有幫助。
e) 同樣你還可以verify HTTP Status code
因為我這個service是需要Content-Type=application/json的, 而我的case裡並沒有賦值給contentType, 所以返回會報錯 415
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
@Test public void testOpenOrder_error() { final String orderNumber = "3017"; final String orderVersion = "1"; final String versionType = ""; final String editUserId = ""; final String customerId = ""; final String state = ""; given(). parameters( "orderNumber", orderNumber, "orderVersion", orderVersion, "versionType", versionType, "editUserId", editUserId, "customerId", customerId, "state", state). expect(). statusCode(415). when(). post("/order/open"); }
f) Cookies 其實都大同小異了
第一個沒有set cookie 結果拋 403
"name":" Forbidden ",
"detail":"The request was a legal request, but the server is refusing to respond to it. Unlike a 401 Unauthorized response, authenticating will make no difference."
@Test public void testCookie() { expect(). statusCode(403). when(). get("/access"); given(). cookie("userName", "wadexu"). expect(). statusCode(200). when(). get("/access"); }
g) Authentication
如果你的service需要認證,則需要設定authentication()
否則401 -- Unauthorized
@Test public void testAuthentication() { expect(). statusCode(401). when(). get("/service/user"); expect(). statusCode(200). when(). with(). authentication().basic("wadexu", "123456"). get("/service/user"); }
H) Specification reuse 規範重用
@Test public void testSpecReuse() { ResponseSpecBuilder builder = new ResponseSpecBuilder(); builder.expectStatusCode(200); builder.expectBody("userInfo.userId", equalTo("wadexu")); builder.expectBody("userInfo.firstName", equalTo("Wade")); builder.expectBody("userInfo.lastName", equalTo("Xu")); builder.expectBody("success", equalTo(true)); ResponseSpecification responseSpec = builder.build(); //use this specification for test example -- a expect(). spec(responseSpec). when(). get("/user/login?userName=wadexu&password=NzrmRcIfIW4="); //now re-use for another example -- c that returns similar data given(). queryParam("userName", "wadexu"). queryParam("password", "NzrmRcIfIW4="). expect(). spec(responseSpec). when(). get("/user/login"); }
如果你還有更多的測試,返回期望結果又類似 則可以繼續使用 specification, 達到重用的目的。
測試執行
Troubleshooting
有些類需要Static imports
參考我的如下:
import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; import com.jayway.restassured.RestAssured; import com.jayway.restassured.builder.ResponseSpecBuilder; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; import com.jayway.restassured.specification.ResponseSpecification; import static com.jayway.restassured.RestAssured.*; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.*;
設定好你的請求url 路徑, 預設http://localhost:8080
參考我的base path(即所以請求url 前面相同的部分) 配置如下:
@Before public void setUp() { RestAssured.baseURI= "http://10.46.28.193"; RestAssured.port = 8080; RestAssured.basePath = "/service/v1"; }
“WARNING: Cannot find parser for content-type: text/json — using default parser.”
– 需要註冊相關的parser: e.g. RestAssured.registerParser(“text/json”, Parser.JSON);
參考來源
使用 Rest-assured 測試 Restful Web Services
這裡向大家介紹一個測試Restful web service 的框架,叫Rest-assured.
他提供了一系列好的功能,像DSL式的語法, XPath-Validate, 檔案上傳,Specification重用, 使用代理, Spring MVC mock module測試Controllers等等,讓你在Java裡面測試Rest service 和那些動態語言Ruby, Groovy一樣靈活。
目錄 1. 前提 2. 配置 3. Example詳解 4. Troubleshooting 5. 參考來源
前提條件
- JDK >= 1.6
- Maven 3
配置Maven工程pom檔案如下
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
Example
a) 測試一個GET 請求方法,
請求URL : http://10.46.28.193:8080/service/v1/user/login
返回JSON內容如下
{ "userInfo": { "password": null, "userId": "wadexu", "accessSecurityCodes": "10000000000000000000", "firstName": "Wade", "lastName": "Xu", "status": 8, "officePhone": "58730", "email": "[email protected]", "homePhone": "123" }, "success": true, "error": null }
測試程式碼如下:
@Before public void setUp() { RestAssured.baseURI= "http://10.46.28.193"; RestAssured.port = 8080; RestAssured.basePath = "/service/v1"; } @Test public void testUserLogin() { expect(). statusCode(200). body( "success", equalTo(true), "userInfo.userId", equalTo("wadexu"), "userInfo.firstName", equalTo("Wade"), "userInfo.lastName", equalTo("Xu"), "error", equalTo(null)). when(). get("/user/login?userName=wadexu&password=NzrmRcIfIW4="); }
注意我這裡請求時的引數直接塞進了URL裡, 稍後會講到如何指明引數。
b) 如何使用JSON path
還是同上面的例子, 測試程式碼如下:
@Test public void testUserLogin_JsonPath() { Response response = get("/user/login?userName=wadexu&password=NzrmRcIfIW4="); assertEquals(200, response.getStatusCode()); String json = response.asString(); JsonPath jp = new JsonPath(json); assertEquals("wadexu", jp.get("userInfo.userId")); assertEquals("Wade", jp.get("userInfo.firstName")); assertEquals("Xu", jp.get("userInfo.lastName")); assertEquals("123", jp.get("userInfo.homePhone")); }
c) 如何使用引數
Get請求是用queryParam, 如果你直接寫 param,在這個case裡也可以,Rest Assured 會自動判斷引數型別(query or form parameter), 在有些case裡, Put 或 Post 你得指明引數型別
@Test public void testUserLogin_Parameter() { final String userName = "wadexu"; final String password = "NzrmRcIfIW4="; given(). queryParam("userName", userName).queryParam("password", password). expect(). statusCode(200). body("success", equalTo(true), "userInfo.userId", equalTo("wadexu"), "userInfo.firstName", equalTo("Wade"), "userInfo.lastName", equalTo("Xu"), "error", equalTo(null)).when() .get("/user/login"); }
另外,有些Post 請求URL後面是有引數的, 這時候 你可以這樣寫
post("/reserve/{hotelId}/{roomNumber}", "My Hotel", 23);
或者
given(). pathParam("hotelId", "My Hotel"). pathParam("roomNumber", 23). when(). post("/reserve/{hotelId}/{roomNumber}"). then(). ..
d) 再來看一個POST 請求, 這時候需要請求訊息體body了,request body是JSON體如下:
{
"customerId": "CDICC",
"broker": "test",
"editUserId": "wadexu"
}
測試程式碼:
@Test public void testCreate() { final String bodyString = "{\"customerId\": \"CDICC\",\"broker\": \"test\",\"editUserId\": \"wadexu\"}"; given(). contentType("application/json"). request().body(bodyString). expect(). statusCode(200). body( "order.orderNumber", is(Number.class), "order.deleteDate", is(nullValue()), "success", equalTo(true)). when(). post("/order"); }
這時除了用到request().body
還多加了一個header 請求訊息頭 -- ContentType
set Headers 的方法有很多, 上面是其一, 你還可以按如下方式做:
given().header("Content-Type", "application/json") given().headers("Accept", "application/json", "Content-Type"