博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
rest-assured实战
阅读量:4304 次
发布时间:2019-05-27

本文共 15767 字,大约阅读时间需要 52 分钟。

前面介绍过了,这篇我们来实战使用下

版本选用4.2.0,目前最新的是4.3.0,但有groovy版本bug。(在使用开源组件时,一定要注意最新版的风险)

使用4.3.0时遇到的bug

在使用开源组件时,遇到bug,可以第一时间去对应的issues里查看下,有时比baidu/google效率高的多

常用的链接

1.常用语法组合

  • 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项目,就不多介绍了,不会可以参照

1.业务代码

1-1.交互类

JsonDataResult类主要为了将返回数据封装成统一固定格式,返回。

public class JsonDataResult
{
protected boolean success; protected String message; protected int errorCode = 0; @JsonProperty("result") protected T data; ...省略了setgeter...}

1-2.实体类

public class UserVo {
private int id; private String name; private Date birthday; private boolean vip; ...省略了setgeter...}

不多解释,一个bean

1-3.controller

UserController类里定义了增删改查接口,并@RestController注解,返回值是json

@RestController@RequestMapping("/api/user")public class UserController {
@PostMapping("/createUserByParam") public JsonDataResult
createUserByParam(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; }}

2.原生rest-assured API

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>

2-1.插入

2-1-1.queryParams方式

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来完成,文章最后会给出此工具类

2-1-2.params方式

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));}

2-1-3.formParams方式

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));}

2-1-4.json方式

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));}

2-2.更新

@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来验证多个结果

2-3.删除

@Testpublic void test003Delete(){
given(). when(). delete("/api/user/{id}",1). then(). statusCode(200). body("result", equalTo(true));}

删除更简单,使用delete

2-4.查询

查询留最后,因为这时我们使用最多,而且使用技巧最多的地方

2-4-1.body验证

@Testpublic void test004GetUserPathParam() {
given(). pathParam("id", 1). when(). get("/api/user/{id}"). then(). statusCode(200). body("result.name", equalTo("iworkh1"));}

直接通过body的path提交值,验证

2-4-2.Response值验证

@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等来验证

2-4-3.转化对象

我们还可以直接将Response转化为对象,来验证处理

通过Response的as方法,参数是类型

  • 类型是普通类: Xxx.class即可
  • 类型是泛型:new TypeRef<Xxx>(){}来转化为需要的对象
@Testpublic void test004GetUserToBean() {
Response response = RestAssuredTool.get("/api/user/3"); JsonDataResult
userVoJsonResult = response.as(new TypeRef
>() {
}); System.out.println(userVoJsonResult.getData()); Assert.assertThat(userVoJsonResult.getData().getName(), equalTo("iworkh3"));}

3.封装rest-assured API

原生rest-assured API使用起来,非常的灵活,但是对于开发者而言,一直...(Fluent风格)的方法调用比较麻烦。

我比较倾向于,调用一个方法,把需要参数都传过去,就结束了,不需要关系底层太多调用,因此对原生的API做下封装

封装好的好处

  • 认证在封装里做,不用在测试代码中去验证
  • 业务测试代码更关注业务,而不用太关注rest-assured的使用

缺点

  • 被封装后的方法,不够灵活。(不灵活,那就原生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
> userVoJsonDataResult = RestAssuredTool.asJsonDataResult(response); System.out.println(userVoJsonDataResult.getData()); Assert.assertThat(userVoJsonDataResult.getData().get("name"), equalTo("iworkh3")); try {
UserVo userVo = BeanMapTool.mapToBean(userVoJsonDataResult.getData(), UserVo.class); Assert.assertThat(userVo.getName(), equalTo("iworkh3")); } catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace(); } } @Test public void test004GetUser04() {
Response response = RestAssuredTool.get(userBaseUrl + 4); // 通过泛型转化为需要的对象 JsonDataResult
userVoJsonResult = RestAssuredTool.asGeneric(response, new TypeRef
>() {
}); Assert.assertThat(userVoJsonResult.getData().getName(), equalTo("iworkh4")); }}

代码中重要的地方都有注释,就不多解释了

4.工具类

4-1.BeanMapTool

bean转map工具类

参照博客

使用的是里面的BeanMapTool工具类

4-2.RestAssuredTool

需要扩展的几个点:

  • port和baseURI修改成从配置文件读取
  • 在初始化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, Map
params) {
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
> asJsonDataResult(Response response) { return response.as(new TypeRef
>>() { }); } public static
T asGeneric(Response response, TypeRef
typeRef) { return response.as(typeRef); } public static
T asCls(Response response, Class
cls) { return response.as(cls); }}

转载地址:http://xzhws.baihongyu.com/

你可能感兴趣的文章
力扣题解-230. 二叉搜索树中第K小的元素(递归方法,中序遍历解决)
查看>>
力扣题解-123. 买卖股票的最佳时机 III(动态规划)
查看>>
Django 源码阅读:服务启动(wsgi)
查看>>
Django 源码阅读:url解析
查看>>
Docker面试题(一)
查看>>
第一轮面试题
查看>>
2020-11-18
查看>>
Docker面试题(二)
查看>>
一、redis面试题及答案
查看>>
消息队列2
查看>>
C++ 线程同步之临界区CRITICAL_SECTION
查看>>
测试—自定义消息处理
查看>>
MFC中关于虚函数的一些问题
查看>>
根据图层名获取图层和图层序号
查看>>
规范性附录 属性值代码
查看>>
提取面狭长角
查看>>
Arcsde表空间自动增长
查看>>
Arcsde报ora-29861: 域索引标记为loading/failed/unusable错误
查看>>
记一次断电恢复ORA-01033错误
查看>>
C#修改JPG图片EXIF信息中的GPS信息
查看>>