Rest-Assured 专注接口测试

前言

对REST Assured的描述如下, 摘自官网:

REST Assured is a Java DSL for simplifying testing of REST based services built on top of HTTP Builder. It supports POST, GET, PUT, DELETE, OPTIONS, PATCH and HEAD requests and can be used to validate and verify the response of these requests.

简明的语法, 使其可以容易的处理requests 和 response, 因此特别适合接口测试

结合BDD模式, 让用例的可读性更强

特点

  • 支持JSON, XML格式
  • 支持GET, GET, PUT, DELETE等请求
  • 丰富的校验规则 (hamcrest语法)

语法结构

given().
        cookie("cookieName", "cookieValue").
        header("Accept", "application/xml");
        param("firstName", "John").
        param("lastName", "Doe").
when().
        post("/greetXML").
then().
        body("greeting.firstName", equalTo("John")).

典型的BDD模式

  • given阶段配置Headers和请求参数
  • when阶段发送请求 (GET, POST, PUT, DELETE等)
  • then阶段校验结果

解析器

用于解析XML 和JSON, 解析方式参考Groovy's path,

shopping.category.find { it.@type == 'groceries' }.item
store.book.findAll { it.price < 10 }.title
store.book.author.collect { it.length() }.sum()

Response对象

获取Response

  • 直接通过get(url), 类似的有post, put, delete等
  • 在then阶段, 使用extract().response(), 即可以在校验完成之后再额外提取响应结果

子属性

有了Response, 就可以获取如请求头部, Cookie对象, 响应结果等

  • response.getHeaders() / response.getHeader(name)
  • Map cookies = response.getCookies() / response.getCookie(name)
  • response.getStatusCode

内容校验

get("/x").then().assertThat().cookie("cookieName", "cookieValue")
get("/x").then().assertThat().statusCode(200)
get("/x").then().assertThat().header("headerName", "headerValue")

REST Assured已集成Hamcrest, 因此可以直接使用

详细的语法可参考http://hamcrest.org/JavaHamcrest/tutorial

响应时间

long timeInSeconds = get("/lotto").timeIn(SECONDS);

when().
      get("/lotto").
then().
      time(lessThan(2L), SECONDS);

抽取结果

有时某些字段并不能直接校验, 需要借助于其他字段, 经过一系列计算

这里, 可以先将中间字段的结果抽取出来

XML

这里就借用官网的例子:

 {
     "title" : "My Title",
      "_links": {
              "self": { "href": "/title" },
              "next": { "href": "/title?page=2" }
           }
 }

调用extract()`方法

String nextTitleLink =
given().
        param("param_name", "param_value").
when().
        get("/title").
then().
        contentType(JSON).
        body("title", equalTo("My Title")).
extract().
        path("_links.next.href");

或者先抽取Response对象, 再通过Response对象获取下面的子元素

Response response = 
given().
        param("param_name", "param_value").
when().
        get("/title").
then().
        contentType(JSON).
        body("title", equalTo("My Title")).
extract().
        response(); 

String nextTitleLink = response.path("_links.next.href");
String headerValue = response.header("headerName");

JSON

与XML类似,

int lottoId = from(response).getInt("lotto.lottoId");
List winnerIds = from(response).get("lotto.winners.winnerId");

实例

先使用springboot编写简易接口

这里只展示Controller内容

@RestController
public class MyController {
    private static Map> container = new HashMap<>();
    private static String bookKey = "books";

    @GetMapping(value="/get")
    public Map getCtl(HttpServletRequest request) {
        Map data = new HashMap<>();

        Enumeration params = request.getParameterNames();
        while(params.hasMoreElements()) {
            String key = params.nextElement();
            String value = request.getParameter(key);
            data.put(key , value);
        }
        return data;
    }

    @PostMapping(value="/nonjson")
    public List returnNonJson() {
        List citys = new ArrayList<>();
        citys.add("Beijing");
        citys.add("Wuhan");
        citys.add("Shanghai");

        return citys;
    }

    @PostMapping(value="/post/xml", produces=MediaType.APPLICATION_XML_VALUE)
    public String postXml() {
        String xml = "" +
                "\n" +
                "      \n" +
                "        Chocolate\n" +
                "        Coffee\n" +
                "      \n" +
                "      \n" +
                "        Paper\n" +
                "        Pens\n" +
                "      \n" +
                "      \n" +
                "        Kathryn's Birthday\n" +
                "      \n" +
                "";
        return xml;
    }

    @PostMapping(value="/post/json",
            produces={MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
    public Map> postJson(String name, float price, String issue) {
        Date _issue;
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            _issue = simpleDateFormat.parse(issue);
        } catch (ParseException e) {
            _issue = new Date();
        }

        Book book = new Book(name, price, _issue);
        if(! container.containsKey(bookKey)) {
            List books = new ArrayList<>();
            books.add(book);
            container.put(bookKey, books);
        } else {
            container.get(bookKey).add(book);
        }
        return container;
    }

    @DeleteMapping(value="/delete")
    public int delete(String name) {
        if(name == null) return 0;

        List books = container.get(bookKey);
        int size = books.size();
        if("_all".equals(name)) {
            books.clear();
            return size;
        } else {
            for(Book book: books) {
                if(book.getName().equals(name)) {
                    books.remove(book);
                }
            }
            return size - books.size();
        }
    }
}

启动程序后, 再来编写测试方法

public class App {
    private final String url = "http://localhost:8080";

    @Test
    public void getTest() {
        given().
                param("hello", "world").
                param("byebye", "winter").
        when().
                get(url + "/get").
        then().
                statusCode(200).
                body(
                        "hello", equalTo("world"),
                        "byebye", equalTo("winter")
                );
    }

    @Test
    public void nonJsonTest() {
        when().
                post(url + "/nonjson").
        then().
                body("$", hasItems("Beijing", "Shanghai", "Wuhan"));
    }

    @Test
    public void postXmlTest() {
        given().
                header("Accept", "application/xml").
        when().
                post(url + "/post/xml").
        then().
                header("Content-Type", "application/xml;charset=UTF-8").
                body("shopping.category.find{it.@type == 'groceries'}.item", hasItems("Chocolate", "Coffee"));
    }

    @Test
    public void postJsonTest() {
        // clear all data
        given().
                param("name", "_all").
        when().
                delete(url + "/delete");

        // Add data
        given().
                param("name", "Java").
                param("price", "36.6").
                param("issue", "2016-03-15")
        .when().
                post(url + "/post/json");

        //Add data
        given().
                param("name", "Python").
                param("price", "25.8").
                param("issue", "2018-07-07")
        .when().
                post(url + "/post/json");

        // Add data and verify
        given().
                param("name", "C++").
                param("price", "19.9").
                param("issue", "2011-02-14")
        .when().
                post(url + "/post/json").
        then().
                body("books.findAll{it.price > 20}.name", hasItems("Java", "Python")).
                body("books.find{it.name == 'Python'}.price", equalTo(25.8f));

    }
}

你可能感兴趣的:(Rest-Assured 专注接口测试)