线下第三期_接口测试进阶_20180916

接口测试进阶

请求构造

GET /stock/search.json?code=sogo HTTP/1.1
Accept: */*
Host: xueqiu.com
Connection: close
User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_51)
Accept-Encoding: gzip, deflate

真实的浏览器请求

GET /stock/search.json?code=sogo HTTP/1.1
Host: xueqiu.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36
Referer: https://xueqiu.com/k?q=sogo
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: device_id=864d4cb52ace61737d69da102e7e996d; _gid=GA1.2.255364479.1537070278; _gat_gtag_UA_16079156_4=1; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1537070292

Get请求常见的请求构造方法

    @Test
    public void request(){
        useRelaxedHTTPSValidation();
        given()
                .proxy("127.0.0.1", 8080)
                .log().all()
                .queryParam("code", "sogo")
                .header("user-agent",
                        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36")
                .header("Accept", "application/json, text/plain, */*")
                .header("Referer", "https://xueqiu.com/k?q=sogo")
                .cookie("xq_a_token", "9c75d6bfbd0112c72b385fd95305e36563da53fb")
        .when()
                .get("https://xueqiu.com/stock/search.json")
        .then()
                .log().all()
                .statusCode(200)
        ;
    }

如果构造json请求需要依赖里添加json相关的库,gson或者jackson都可以

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>
``
## 断言机制
JsonPath: http://static.javadoc.io/io.rest-assured/json-path/3.1.1/io/restassured/path/json/JsonPath.html

```java
package offline3;

import org.junit.Test;
import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static org.hamcrest.Matchers.*;

public class TesterHomeTest {

    @Test
    public void demo(){
        useRelaxedHTTPSValidation();
        int limit=10;
        given()
                .queryParam("limit", limit)
        .when()
                .get("https://testerhome.com/api/v3/topics.json")
        .then()
            .statusCode(200)
            .body("topics.size()", equalTo(3+limit))
            .body("topics[0].id", equalTo(16142))
            .body("topics.find { x -> x.id > 16141 }.title ",
                    equalTo("技术沙龙招募:从研发到测试,手把手教你打造绿色应用"))
            .body("topics.findAll { x -> x.id > 16141 }.title[0] ",
                        equalTo("技术沙龙招募:从研发到测试,手把手教你打造绿色应用"))
            .body("topics.findAll{ it.title == '技术沙龙招募:从研发到测试,手把手教你打造绿色应用'}.size()",
                    equalTo(1))
            .body("topics.title", hasItems(
                    "技术沙龙招募:从研发到测试,手把手教你打造绿色应用",
                    "美团技术沙龙北京站:千万级日活 App 的质量保证"))
        ;
    }
}

断言失败继续下一个断言

package offline3;

import io.restassured.response.Response;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;

import static io.restassured.RestAssured.given;
import static io.restassured.RestAssured.useRelaxedHTTPSValidation;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;

public class AssertionTest {
    @Rule
    public ErrorCollector collector = new ErrorCollector();


    @Test
    public void assertionThats(){
        assertThat(1, equalTo(2));
        assertThat(2, equalTo(2));
        assertThat(3, equalTo(2));
    }
    @Test
    public void assertions(){
        collector.checkThat(1, equalTo(2));
        collector.checkThat(2, equalTo(2));
        collector.checkThat(3, equalTo(2));
    }


    @Test
    public void extract(){
        useRelaxedHTTPSValidation();
        int limit=10;
        Response response=given().proxy("127.0.0.1", 8080)
                .queryParam("limit", limit)
                .when()
                .get("https://testerhome.com/api/v3/topics.json")
                .then()
                .statusCode(200)
                .extract().response();

        System.out.println(response.path("topics[0]").toString());
        System.out.println((Integer) response.path("topics[-1].id"));

    }

    @Test
    public void assertion(){
        useRelaxedHTTPSValidation();
        int limit=10;
        Response response=given().proxy("127.0.0.1", 8080)
                .queryParam("limit", limit)
                .when()
                .get("https://testerhome.com/api/v3/topics.json")
                .then()
                .extract().response();

        collector.checkThat(response.statusCode(), equalTo(400));
        collector.checkThat(response.path("topics.size()"), equalTo(3+limit));
        collector.checkThat(response.path("topics[0].id"), equalTo(16142));
        collector.checkThat(response.path("topics.find { x -> x.id > 16141 }.title "),
                        equalTo("技术沙龙招募:从研发到测试,手把手教你打造绿色应用"));
        collector.checkThat(response.path("topics.findAll { x -> x.id > 16141 }.title[0] "),
                        equalTo("技术沙龙招募:从研发到测试,手把手教你打造绿色应用_error"));
        collector.checkThat(response.path("topics.findAll{ it.title == '技术沙龙招募:从研发到测试,手把手教你打造绿色应用'}.size()"),
                        equalTo(1));
        collector.checkThat(response.path("topics.title"), hasItems(
                        "技术沙龙招募:从研发到测试,手把手教你打造绿色应用",
                        "美团技术沙龙北京站:千万级日活 App 的质量保证"));
        ;


    }
}

返回值类型设置

    @Test
    public void quote(){
        given()
                .config(RestAssuredConfig.config().jsonConfig(JsonConfig.jsonConfig().numberReturnType(JsonPathConfig.NumberReturnType.DOUBLE)))
                .queryParam("symbol", "SH000001,HKHSI,.INX")
                .cookie("xq_a_token", "9c75d6bfbd0112c72b385fd95305e36563da53fb")
            .when()
                .get("https://stock.xueqiu.com/v5/stock/batch/quote.json")
            .then()
                .log().all()
                .statusCode(200)
                .body("data.items.quote.find { it.symbol == 'SH000001'}.name", equalTo("上证指数"))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current", equalTo( 2681.64))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current", closeTo( 2681.64, 100))
        ;
    }

调用函数转换

    @Test
    public void quote(){
        given()
                //.config(RestAssuredConfig.config().jsonConfig(JsonConfig.jsonConfig().numberReturnType(JsonPathConfig.NumberReturnType.DOUBLE)))
                .queryParam("symbol", "SH000001,HKHSI,.INX")
                .cookie("xq_a_token", "9c75d6bfbd0112c72b385fd95305e36563da53fb")
            .when()
                .get("https://stock.xueqiu.com/v5/stock/batch/quote.json")
            .then()
                .log().all()
                .statusCode(200)
                .body("data.items.quote.find { it.symbol == 'SH000001'}.name", equalTo("上证指数"))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current", equalTo( 2681.64f))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current.toDouble()", closeTo( 2681.64, 100))
        ;
    }

认证

basic测试网址:http://jenkins.testing-studio.com:9001/

FIlter机制

修改请求,自动添加cookie、header,以及自动更新的token

    @Test
    public void requestFilter() {
        filters((new Filter() {
                    @Override
                    public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec, FilterContext ctx) {
                        System.out.println("request filter");
                        System.out.println(requestSpec.getQueryParams());
                        requestSpec.queryParam("symbol", "SH000002");
                        Response response = ctx.next(requestSpec, responseSpec);
                        System.out.println("response filter");
                        return response;

                    }
                })
        );


        given()
                .log().all()
                //.config(RestAssuredConfig.config().jsonConfig(JsonConfig.jsonConfig().numberReturnType(JsonPathConfig.NumberReturnType.DOUBLE)))
                .queryParam("symbol", "SH000001,HKHSI,.INX")
                .cookie("xq_a_token", "9c75d6bfbd0112c72b385fd95305e36563da53fb")
                .when()
                .get("https://stock.xueqiu.com/v5/stock/batch/quote.json")
                .then()
                .log().all()
                .statusCode(200)
                .body("data.items.quote.find { it.symbol == 'SH000001'}.name", equalTo("上证指数"))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current", equalTo(2681.64f))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current.toDouble()", closeTo(2681.64, 100))
        ;
    }

修改响应,可以用于接口解密,响应头信息的修改,以及其他协议的测试。

    @Test
    public void reponseFilter(){

        filters((new Filter() {
                    @Override
                    public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec, FilterContext ctx) {
                        Response response = ctx.next(requestSpec, responseSpec);
                        System.out.println("origin response");
                        System.out.println(response.getBody().asString());

                        System.out.println("decode response");
                        String contentDecode=new String(Base64.decodeBase64(response.getBody().asString()));
                        System.out.println(contentDecode);

                        Response newResponse = new ResponseBuilder().clone(response)
                                .setContentType(ContentType.JSON)
                                .setBody(contentDecode)
                                .build();
                        System.out.println("response filter");
                        System.out.println(newResponse.getBody().asString());

                        return newResponse;

                    }
                })
        );



        given()
                .proxy("127.0.0.1", 8080)
                .auth().basic("hogwarts", "123456")
        .when()
                .get("http://jenkins.testing-studio.com:9001/base64.json")
        .then()
                .log().all()
                .statusCode(200)
                .body("data.items.quote.find { it.symbol == 'SH000001'}.name", equalTo("上证指数"))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current", equalTo(2681.64f))
                .body("data.items.quote.find { it.symbol == 'SH000001'}.current.toDouble()", closeTo(2681.64, 100))
        ;
    }

数据驱动

用例维护

作业

  • https://testerhome.com/api/v3/topics.json?limit=20 从这个接口中找出来title是“美团技术沙龙北京站:千万级日活 App 的质量保证”的作者
  • 用自己的浏览器访问雪球,找到quote.json接口,对它进行基础的一个查询测试,断言对应的股票的基础属性。
  • 实现自动登陆jenkins,并自动更新每个后续请求的cookie,以触发demo job的构建为例 http://jenkins.testing-studio.com:8081/job/demo/
  • 实现http://jenkins.testing-studio.com:9001/base64base64.json 解密并进行结果断言

相关数据

POST /j_acegi_security_check HTTP/1.1
Host: jenkins.testing-studio.com:8081
Connection: keep-alive
Content-Length: 311
Pragma: no-cache
Cache-Control: no-cache
Origin: http://jenkins.testing-studio.com:8081
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://jenkins.testing-studio.com:8081/login?from=%2F
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: jenkins-timestamper-offset=-28800000; _ga=GA1.2.2053923289.1527161186; screenResolution=1440x900; JSESSIONID.2982ccf6=node0fmmrgi81enzz3ga6av8u1r9h36.node0

j_username=demo&j_password=demo&from=%2F&Jenkins-Crumb=fbb99db66b17e444aae303caa1076982&json=%7B%22j_username%22%3A+%22demo%22%2C+%22j_password%22%3A+%22demo%22%2C+%22remember_me%22%3A+false%2C+%22from%22%3A+%22%2F%22%2C+%22Jenkins-Crumb%22%3A+%22fbb99db66b17e444aae303caa1076982%22%7D&Submit=%E7%99%BB%E5%BD%95

触发job构建的命令

curl 'http://jenkins.testing-studio.com:8081/job/demo/build'  \\
-H 'Origin: http://jenkins.testing-studio.com:8081' \\
-H 'Cookie: jenkins-timestamper-offset=-28800000; _ga=GA1.2.2053923289.1527161186; screenResolution=1440x900; JSESSIONID.2982ccf6=node0oegox25ng1u7e971e3gah7mw37.node0' \\
--data 'Jenkins-Crumb=d8f8afd502f2e5eeb19cbb5f8482a15b&json=%7B%22Jenkins-Crumb%22%3A+%22d8f8afd502f2e5eeb19cbb5f8482a15b%22%7D' \\
--compressed
关闭