本文共 15767 字,大约阅读时间需要 52 分钟。
前面介绍过了,这篇我们来实战使用下
版本选用
4.2.0
,目前最新的是4.3.0
,但有groovy版本bug。(在使用开源组件时,一定要注意最新版的风险)
使用4.3.0时遇到的bug
在使用开源组件时,遇到bug,可以第一时间去对应的issues里查看下,有时比baidu/google效率高的多
常用的链接
given()--when()--then()
given()--expect()--when()
given
里设置参数、头、认证when()
里请求rest接口,get、post、put、delete等expect()
和then()
里验证结果。
given()–expect()–when()
given(). param("x", "y").expect(). statusCode(400). body("lotto.lottoId", equalTo(6)).when(). get("/lotto");
given()–when()–then()
given(). param("x", "y").when(). get("/lotto").then(). statusCode(400). body("lotto.lottoId", equalTo(6));
方法调用链图:
看不懂这图,可以先不用急,看完下面rest-assured原生的api如何使用后,再来看这张图可能对方法间调用关系就明白了。为了更好的演示,创建个springboot的web项目,为了简化,只有controller层和domain层,没有service和dao的逻辑。
如何创建springboot项目,就不多介绍了,不会可以参照
JsonDataResult类主要为了将返回数据封装成统一固定格式,返回。
public class JsonDataResult{ protected boolean success; protected String message; protected int errorCode = 0; @JsonProperty("result") protected T data; ...省略了setgeter...}
public class UserVo { private int id; private String name; private Date birthday; private boolean vip; ...省略了setgeter...}
不多解释,一个bean
UserController类里定义了增删改查接口,并@RestController
注解,返回值是json
@RestController@RequestMapping("/api/user")public class UserController { @PostMapping("/createUserByParam") public JsonDataResultcreateUserByParam(UserVo userVo) { JsonDataResult result = new JsonDataResult<>(); userVo.setId(new Random().nextInt(50)); result.setSuccess(true); result.setData(true); return result; } @PostMapping("/createUserByJson") public JsonDataResult createUserByJson(@RequestBody UserVo userVo) { JsonDataResult result = new JsonDataResult<>(); userVo.setId(new Random().nextInt(100)); result.setSuccess(true); result.setData(true); return result; } @GetMapping("/{id}") public JsonDataResult getUser(@PathVariable int id) { JsonDataResult result = new JsonDataResult<>(); String[] hobbies = { "football", "sing"}; //从数据库查询,省略 UserVo user = new UserVo(id, "iworkh" + id, System.currentTimeMillis(), true, Arrays.asList(hobbies)); result.setSuccess(true); result.setData(user); return result; } @PutMapping public JsonDataResult updateUser(@RequestBody UserVo userVo) { JsonDataResult result = new JsonDataResult<>(); //从数据库删除,省略 result.setSuccess(true); result.setData(userVo); return result; } @DeleteMapping("/{id}") public JsonDataResult delteUser(@PathVariable int id) { JsonDataResult result = new JsonDataResult<>(); //从数据库删除,省略 result.setSuccess(true); result.setData(true); return result; }}
RestAssured
类是很关键的一个类,打开发现很多方法,和默认配置,这里提下几个默认配置
DEFAULT_URI
: 默认值是 http://localhost
DEFAULT_PORT
: 默认值是 8080
所以,当我们端口号不是默认值时,我们也得修改配置。(比如:
RestAssured.port = 9090;
)
为了简单演示,一些认证都不打开了。直接演示调用rest接口测试。
引入依赖
io.rest-assured rest-assured ${rest-assured.version} test json-path io.rest-assured xml-path io.rest-assured io.rest-assured json-path ${rest-assured.version} test io.rest-assured xml-path ${rest-assured.version} test
其中rest-assured的版本是4.2.0
<rest-assured.version>4.2.0</rest-assured.version>
queryParams:即通过url后面加参数方式传递
@Testpublic void test001CreateUserByUrl() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); given(). queryParams(BeanMapTool.beanToMap(zhangsanUser)). when(). post("/api/user/createUserByParam"). then(). statusCode(200). body("result", equalTo(true));}
XxxParmas方法需要的是一个Map对象,所以可以使用Map初始化值传递。
BeanMapTool.beanToMap()是个工具类,可以将bean转化为Map,使用的是org.springframework.cglib.beans.BeanMap
来完成,文章最后会给出此工具类
queryParams:即通过post参数方式
@Testpublic void test001CreateUserByParam() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); given(). params(BeanMapTool.beanToMap(zhangsanUser)). when(). post("/api/user/createUserByParam"). then(). statusCode(200). body("result", equalTo(true));}
formParams:即通过post form表单方式
@Testpublic void test001CreateUserByFormParam() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); given(). formParams(BeanMapTool.beanToMap(zhangsanUser)). when(). post("/api/user/createUserByParam"). then(). statusCode(200). body("result", equalTo(true));}
contentType:指定json格式,并body传数据。(body的值,不一定json字符串,是对象也可以)
@Testpublic void test003CreateUserByJson() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); given(). contentType(ContentType.JSON).body(zhangsanUser). when(). post("/api/user/createUserByJson"). then(). statusCode(200). body("result", equalTo(true));}
@Testpublic void test002Update(){ String[] hobbies = { "football", "play games"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); given(). contentType(ContentType.JSON).body(zhangsanUser). when(). put("/api/user/"). then(). statusCode(200). body("result.hobbies", hasItems("football", "play games"));}
更新比较简单,使用
put
来更新,验证使用hasItems
来验证多个结果
@Testpublic void test003Delete(){ given(). when(). delete("/api/user/{id}",1). then(). statusCode(200). body("result", equalTo(true));}
删除更简单,使用
delete
查询留最后,因为这时我们使用最多,而且使用技巧最多的地方
@Testpublic void test004GetUserPathParam() { given(). pathParam("id", 1). when(). get("/api/user/{id}"). then(). statusCode(200). body("result.name", equalTo("iworkh1"));}
直接通过body的path提交值,验证
@Testpublic void test004GetUserExactResponse() { Response response= given(). expect(). statusCode(200). when(). get("/api/user/2"); String name = response.path("result.name"); Assert.assertThat(name, equalTo("iworkh2"));}
直接根据Response的返回值,自己解析Response里header、body等来验证
我们还可以直接将Response转化为对象,来验证处理
通过Response的as方法,参数是类型
Xxx.class
即可new TypeRef<Xxx>(){}
来转化为需要的对象@Testpublic void test004GetUserToBean() { Response response = RestAssuredTool.get("/api/user/3"); JsonDataResultuserVoJsonResult = response.as(new TypeRef >() { }); System.out.println(userVoJsonResult.getData()); Assert.assertThat(userVoJsonResult.getData().getName(), equalTo("iworkh3"));}
原生rest-assured API使用起来,非常的灵活,但是对于开发者而言,一直...
(Fluent风格)的方法调用比较麻烦。
我比较倾向于,调用一个方法,把需要参数都传过去,就结束了,不需要关系底层太多调用,因此对原生的API做下封装
封装好的好处
缺点
文章最后,给出封装好的
RestAssuredTool
类,当然这封装的不一定满足所有场合,也不是最好的。(大家可根据自己的需求来封装,这只抛砖引玉下)
调用封装后的测试类
package com.iworkh.test.restassured.controller;import com.iworkh.test.restassured.domain.vo.JsonDataResult;import com.iworkh.test.restassured.domain.vo.UserVo;import com.iworkh.test.restassured.utils.BeanMapTool;import com.iworkh.test.restassured.utils.RestAssuredTool;import io.restassured.common.mapper.TypeRef;import io.restassured.response.Response;import org.junit.Assert;import org.junit.FixMethodOrder;import org.junit.Test;import org.junit.runners.MethodSorters;import java.util.Arrays;import java.util.Map;import static org.hamcrest.Matchers.equalTo;/** * UserController测试类 * * @author: iworkh-沐雨云楼 * @date: 2020-06-18 */@FixMethodOrder(MethodSorters.NAME_ASCENDING)public class UserControllerTest { private String userBaseUrl = "/api/user"; @Test public void test001CreateUserByParam() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); Response resp = RestAssuredTool.postWithParams(userBaseUrl + "/createUserByParam", BeanMapTool.beanToMap(zhangsanUser)); RestAssuredTool.validateStatusCode(resp, 200); RestAssuredTool.validateEqualTo(resp, "result", true); } @Test public void test001CreateUserByJson() { String[] hobbies = { "football", "sing"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); Response resp = RestAssuredTool.postWithJson(userBaseUrl + "/createUserByJson", zhangsanUser); RestAssuredTool.validateStatusCode(resp, 200); } @Test public void test002Upate() { String[] hobbies = { "football", "play games"}; UserVo zhangsanUser = new UserVo(1, "zhangsan", System.currentTimeMillis(), false, Arrays.asList(hobbies)); Response response = RestAssuredTool.putWithJson(userBaseUrl, zhangsanUser); RestAssuredTool.validateStatusCode(response, 200); } @Test public void test003Delete() { Response response = RestAssuredTool.delete(userBaseUrl + "/id"); RestAssuredTool.validateStatusCode(response, 200); } @Test public void test004GetUser01() { Response resp = RestAssuredTool.get(userBaseUrl + 1); RestAssuredTool.validateHasItems(resp, "result.hobbies", "football", "sing"); } @Test public void test004GetUser02() { Response response = RestAssuredTool.get(userBaseUrl + 2); int id = response.path("result.id"); Assert.assertThat(id, equalTo(2)); } @Test public void test004GetUser03() { Response response = RestAssuredTool.get(userBaseUrl + 3); // 转化为JsonDataResult对象,不过data部分是map,再使用BeanMapTool工具可以转为对对应的对象 JsonDataResult
代码中重要的地方都有注释,就不多解释了
bean转map工具类
参照博客
使用的是里面的BeanMapTool工具类
需要扩展的几个点:
restClient
时,将认证加上其他如何操作可以查看官网或者查看翻译的wiki
package com.iworkh.test.restassured.utils;import com.iworkh.test.restassured.domain.vo.JsonDataResult;import io.restassured.RestAssured;import io.restassured.common.mapper.TypeRef;import io.restassured.http.ContentType;import io.restassured.http.Headers;import io.restassured.path.json.JsonPath;import io.restassured.path.json.config.JsonPathConfig;import io.restassured.response.Response;import io.restassured.specification.RequestSpecification;import java.util.Map;import static io.restassured.RestAssured.given;import static org.hamcrest.Matchers.equalTo;import static org.hamcrest.Matchers.hasItems;/** * RestAssuredTool工具类 * * @author: iworkh-沐雨云楼 * @date: 2020-06-18 */public class RestAssuredTool { static { // 这可以修改为从配置文件读取 String siteBaseURI = "http://localhost"; int port = 8080; RestAssured.baseURI = siteBaseURI; RestAssured.port = port; JsonPath.config = new JsonPathConfig("UTF-8"); } public static RequestSpecification restClient() { // 认证等操作,都可以在这统一处理 return given(); } public static RequestSpecification restClientWithHeader(Headers headers) { // 认证等操作,都可以在这统一处理 return given().headers(headers); } // get public static Response get(String url) { return restClient().get(url); } public static Response getWithParams(String url, Mapparams) { return restClient().params(params).get(url); } public static Response getWithQueryParams(String url, Map params) { return restClient().queryParams(params).get(url); } public static Response getWithFormParams(String url, Map params) { return restClient().formParams(params).get(url); } public static Response getWithJson(String url, T data) { return restClient().contentType(ContentType.JSON).body(data).get(url); } // post public static Response postWithParams(String url, Map params) { return restClient().params(params).post(url); } public static Response postWithFormParams(String url, Map params) { return restClient().formParams(params).post(url); } public static Response postWithJson(String url, T data) { return restClient().contentType(ContentType.JSON).body(data).post(url); } // put public static Response putWithParams(String url, Map params) { return restClient().params(params).put(url); } public static Response putWithFormParams(String url, Map params) { return restClient().formParams(params).put(url); } public static Response putWithJson(String url, T data) { return restClient().contentType(ContentType.JSON).body(data).put(url); } // delete public static Response delete(String url) { return restClient().delete(url); } public static Response deleteWithJson(String url, T data) { return restClient().contentType(ContentType.JSON).body(data).delete(url); } // validate response public static void validateStatusCode(Response response, int expectedStatusCode) { response.then().statusCode(expectedStatusCode); } public static void validateEqualTo(Response response, String path, T expectedValue) { response.then().body(path, equalTo(expectedValue)); } public static void validateHasItems(Response response, String path, T... expectedValue) { response.then().body(path, hasItems(expectedValue)); } // convert public static JsonDataResult
转载地址:http://xzhws.baihongyu.com/