参考来源:https://blog.csdn.net/u011622109/article/details/106904955
文档翻译: https://iworkh.gitee.io/blog/2020/06/17/java_rest_assured_wiki_info/
一、被测试的接口准备,来自于上面的参考,spring boot框架
响应类
import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class JsonDataResult<T> { protected boolean success; protected String message; protected int errorCode = 0; @JsonProperty("result") protected T data; }
实体类
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor public class UserVo { private int id; private String name; private Date birthday; private boolean vip; }
controller
import com.example.demo.pojo.JsonDataResult; import com.example.demo.pojo.UserVo; import org.springframework.web.bind.annotation.*; import java.util.Date; import java.util.Random; @RestController @RequestMapping("/api/user") public class UserController { @PostMapping("/createUserByParam") public JsonDataResult<Boolean> createUserByParam(UserVo userVo) { JsonDataResult<Boolean> result = new JsonDataResult<>(); userVo.setId(new Random().nextInt(50)); result.setSuccess(true); result.setData(true); return result; } @PostMapping("/createUserByJson") public JsonDataResult<Boolean> createUserByJson(@RequestBody UserVo userVo) { JsonDataResult<Boolean> result = new JsonDataResult<>(); userVo.setId(new Random().nextInt(100)); result.setSuccess(true); result.setData(true); return result; } @GetMapping("/{id}") public JsonDataResult<UserVo> getUser(@PathVariable int id) { JsonDataResult<UserVo> result = new JsonDataResult<>(); String[] hobbies = {"football", "sing"}; //从数据库查询,省略 UserVo user = new UserVo(id, "测试名字" + id, new Date(), true); result.setSuccess(true); result.setData(user); return result; } @PutMapping public JsonDataResult<UserVo> updateUser(@RequestBody UserVo userVo) { JsonDataResult<UserVo> result = new JsonDataResult<>(); //从数据库删除,省略 result.setSuccess(true); result.setData(userVo); return result; } @DeleteMapping("/{id}") public JsonDataResult<Boolean> delteUser(@PathVariable int id) { JsonDataResult<Boolean> result = new JsonDataResult<>(); //从数据库删除,省略 result.setSuccess(true); result.setData(true); return result; } }
二、依赖,杂七杂八一堆
<dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>4.4.0</version> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>json-path</artifactId> <version>4.4.0</version> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>json-schema-validator</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>xml-path</artifactId> <version>4.4.0</version> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>4.4.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured-common</artifactId> <version>4.4.0</version> <scope>compile</scope> </dependency>
三、语法链
given()--when()--then()
1、given 后面, 设置参数、头、认证
2、when() 后面, 请求rest接口,get、post、put、delete等
3、then() 后面, 验证结果。
四、2个静态引用,一个是框架本身,一个是用于校验使用
// 官方推荐静态引用 import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*;
五、入参
@Test public void testParams() { // 1、given() 是RestAssured类下一个方法,官方文档强烈推荐使用静态导入语句 // 2、get方法,对应GET请求,这一步已经请求完成了 // 3、then() 为后面对response消息做判断时做准备 HashMap<String, String> params = new HashMap<String, String>(); params.put("userId", "2"); params.put("id", "14"); HashMap<String, String> headers = new HashMap<String, String>(); headers.put("accept-encoding", "gzip,deflate"); headers.put("accept-language", "zh-CN"); given(). // 调用效果:http://jsonplaceholder.typicode.com/posts?id=14&userId=2 // 这个貌似和params一样的效果 queryParams(params). // params(params). // param只能设置一个参数,多调用几次可以多设置几个参数,下面的header类似 // param("userId", 2). // 多个头字段 headers(headers). // header("accept-encoding", "gzip,deflate"). when(). // 请求前的log 是打印请求参数信息 // log().all(). get("http://jsonplaceholder.typicode.com/posts"). then(). // 请求后的log 是打印响应参数信息 log().body(); }
@Test public void testAssert() { given(). // 效果 http://jsonplaceholder.typicode.com/posts/3 // 把下面地址中的变量替换掉 pathParam("section", "posts"). pathParam("id", "3"). when(). get("http://jsonplaceholder.typicode.com/{section}/{id}");
}
@Test public void test0011() { UserVo user = new UserVo(1, "zhangsan", new Date(), false); given(). // 直接传入对象 body(user). // 两种设置入参类型 header("Content-Type", "application/json; charset=utf-8"). // contentType("application/json; charset=utf-8"); when(). post("/api/user/createUserByParam");
}
六、响应信息处理
@Test public void test001() { // 这里没有设置baseurl,但是依然请求成功了。因为框架有默认的url:http://localhost:8080 Response response = get("/api/user/3"); // 使用 as 将响应转化为我们需要的对象 JsonDataResult j = response.as(JsonDataResult.class); // 拿到响应后也可以用testng本身的断言 Assert.assertEquals(j.isSuccess(),true); }
@Test public void testResponse() { // 在没有参数设置的前提下,可以直接请求,拿到响应 Response r = get("https://reqres.in/api/users/2"); System.out.println("直接获取的响应结果:" + r.asString()); System.out.println("获取请求头:" + r.getHeaders()); System.out.println("获取请求头某个字段:" + r.getHeader("Content-Type")); System.out.println("获取cookies:" +r.cookies()); System.out.println("毫秒:" + r.time()); System.out.println("毫秒,会损失精度:" + r.timeIn(TimeUnit.SECONDS)); Integer id = r. then(). // json、xm都可以使用xpath路径 body("data.id", is(2)). // 通过extract().path() 摘取内容 extract(). path("data.id"); Response response = r. then(). extract(). response(); System.out.println("间接获取到的响应和直接获取的响应比较:" + ( response == r )); System.out.println("间接获取到的id和直接获取的id比较:" + ( id == r.path("data.id") )); }
七、框架自带的响应断言
@Test public void testAssert() { given(). pathParam("section", "posts"). pathParam("id", "3"). when(). get("http://jsonplaceholder.typicode.com/{section}/{id}"). then(). // 下面的断言是线性断言,一旦某个断言失败,后面就不会继续执行 //断言200 statusCode(200). // 断言返回的格式对象,例如XML、HTML、TEXT等 contentType(ContentType.JSON). // 断言响应头字段,header单个,headers多个 header("Content-Type", "application/json; charset=utf-8"). headers("Content-Type", "application/json; charset=utf-8", "Connection", "keep-alive"). // Matchers提供了很多匹配方式,equalTo、containsString。hasItem、hasItems这2个我没用成功 body(containsString("ea molestias quasi exercitationem")). body("userId", equalTo(1)). // body("title", hasItem("ea molestias quasi exercitationem repellat qui ipsa sit aut")). // 不同节点相同的key有对应的value,例如:{{"title": "value1"},{"title": "value2"}}, // 则不能使用equalTo、hasItem,可以使用hasItems(要求把所有的value列出来) // body("title", hasItems("ea molestias quasi exercitationem repellat qui ipsa sit aut")). // 断言响应时间小于2000毫秒,参数类型是long time(lessThan(2000L)). log().body(); }
八、base信息设置、请求封装RequestSpecification、响应封装ResponseSpecification
public class TC41 { RequestSpecification requestSpc; ResponseSpecification responseSpc; @BeforeClass public void setup() { // 这里设置了 baseURI、basePath,后面get则不需要再填这2个信息 RestAssured.baseURI = "http://jsonplaceholder.typicode.com"; // RestAssured.port = 80; RestAssured.basePath = "/posts"; // 恢复成默认设置 // RestAssured.reset(); // 利用RequestSpecification对象来封装一些请求数据 RequestSpecBuilder builder = new RequestSpecBuilder(); builder.addParam("userId", "2"); builder.addHeader("Accept-Encoding", "gzip, deflate"); requestSpc = builder.build(); // 利用ResponseSpecification对象来封装一些响应判断的数据 ResponseSpecBuilder rb = new ResponseSpecBuilder(); rb.expectStatusCode(200); rb.expectHeader("Content-Type", "application/json; charset=utf-8"); rb.expectHeader("Cache-Control", "max-age=43200"); responseSpc = rb.build(); } @Test public void test1() { given(). spec(requestSpc).log().all(). when(). get(). then(). spec(responseSpc). // 如果错误就打印日志 log().ifError(); } }
九、其他内容
public class TestBase { public static RequestSpecification httpRequest; public static Response response; public Logger logger; public static String serverHost; public static String port; // 静态代码块,随着类的加载而执行,而且只执行一次 static { // 用于加载properties文件,入参不需要文件扩展名.properties ResourceBundle rb = ResourceBundle.getBundle("config"); serverHost = rb.getString("Host"); port = rb.getString("Port"); } @BeforeClass public void setup() { String className = this.getClass().getName(); logger = Logger.getLogger(className); // PropertyConfigurator.configure("log4j.properties"); // logger.setLevel(Level.DEBUG); // logger.info("host: " + serverHost); // logger.info("port: " + port); } }