jck28 - 小柒 - 接口测试mock

一,mock测试

参考文档:
接口测试——接口协议抓包分析与mock_L3_303 接口协议-CSDN博客

1,mock的价值

  • 不依赖第三方数据
  • 节省工作量
  • 节省联调

2,常用的mock工具

  • Charles 测试工程师常用
  • BurpSuite 黑客常用
  • Fiddler 只能 Windows 上使用
  • Nginx 服务器反向代理与修改
  • Mitmproxy 代理工具 可编程
  • Wiremock 代理工具 可编程

3,mock实战 - Charles工具

3.1 Rewrite方式

原理:

设置方法:

  • Tools → Rewrite
  • 勾选 Enable Rewrite
  • 点击下方 Add 按钮新建一个重写的规则
  • 在右侧编辑重写规则
  • 点击 ok 生效

3.2 Map Local 方式

原理:

设置方法:

  • 准备本地接口响应数据
  • 配置 Map Local
    • 选择要进行 Map Local 的接口
    • 鼠标右键 – 选择 Map Local 选项进入设置界面
    • Map From 填写接口的信息
    • Map To 选择本地文件
  • 修改 Map Local 配置:Tools – Map Local

3.3 Map Remote 方式

原理:

设置方法:

  • 选择接口,点击鼠标右键,选择 Map Remote 进入到设置页面
  • 设置重定向的接口信息
  • 点击 ok 生效
  • 修改设置:Tools – Map Remote 找对对应接口双击进入修改界面

4,mock实战 - WireMock

4.1 依赖导入

        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.5.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.tomakehurst</groupId>
            <artifactId>wiremock-jre8</artifactId>
            <version>2.32.0</version>
            <scope>test</scope>
        </dependency>

4.2 使用的 mock流程模板

import com.github.tomakehurst.wiremock.WireMockServer;  
import com.github.tomakehurst.wiremock.client.WireMock;  
  
import org.junit.jupiter.api.Test;  
  
import static com.github.tomakehurst.wiremock.client.WireMock.*;  
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;


//启动服务的端口号
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089)); //No-args constructor will start on port 8080, no HTTPS
wireMockServer.start();
configureFor(8089);
// 做一些业务请求逻辑
...

WireMock.reset();

// 完成之后
wireMockServer.stop();

4.2 实战 - mock发送一个请求,请求参数匹配规则

调用下记代码发送请求,然后通过浏览器输入“localhost:8089”,回车查看返回结果是否与body内容匹配


import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;

public class WireMockTest {

    @Test
    void baseMockTest() throws InterruptedException {
        //启动服务的端口号
        WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
        //No-args constructor will start on port 8080, no HTTPS(没有定义端口号的情况下,默认端口号是8080)
        wireMockServer.start();
        configureFor(8089);
        //业务逻辑 - 写一个get请求,要求其返回body体的内容
        stubFor(get(urlEqualTo("/wiremock"))
                .willReturn(aResponse().withBody("this is a mock server")));
        Thread.sleep(999999);
        //重置数据
        WireMock.reset();
        // 完成之后
        wireMockServer.stop();
    }


    @Test
    void baseMock404Test() throws InterruptedException {
        //启动服务的端口号
        WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
        //No-args constructor will start on port 8080, no HTTPS(没有定义端口号的情况下,默认端口号是8080)
        wireMockServer.start();
        configureFor(8089);
        //业务逻辑 - 写一个get请求,定义状态码不同,返回body体的内容不同
        stubFor(get(urlEqualTo("/wiremock"))
                .willReturn(aResponse().withStatus(404).withBody("this is a mock server  404")));
        Thread.sleep(999999);
        //重置数据
        WireMock.reset();
        // 完成之后
        wireMockServer.stop();
    }
}

4.3 实战 - mock发送一个带请求参数的请求,请求参数匹配规则

  • 调用下记mock发起请求
@Test
    void requestMock() throws InterruptedException {
        WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
        wireMockServer.start();
        configureFor(8089);
        // any - 希望匹配任何请求方法,带参数的请求必须用urlPathEqualTo
        stubFor(any(urlPathEqualTo("/wiremock"))
                .withHeader("Accept",containing("xml"))
                .withCookie("session",matching(".*12345*"))
                .withQueryParam("search_term",equalTo("WireMock"))
                .withBasicAuth("demi@ceshiren.com","hogwarts1234")
                .withRequestBody(matchingJsonPath("$.a",equalTo("1")))
                .willReturn(aResponse().withStatus(200).withBody("request mock server !!"))
        );
        //强制等待
        sleep(999999);
        WireMock.reset();
        wireMockServer.stop();

    }

  • mock一个匹配上述规则的请求并调用,通过浏览器查看对应接口请求传参和返回响应是否匹配
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;

public class RequestTest {
    @Test
    void requestTest(){
        given().log().all()
                .header("Accept","xml")
                .cookie("session","12345")
                .queryParam("search_term","WireMock")
                .auth().preemptive().basic("demi@ceshiren.com","hogwarts1234")
                .body("{a:1,b:99,c:2}")
                .when()
                .post("http://localhost:8089/wiremock")
                .then().log().all();
    }

}

4.4 实战 - 发送多个请求并返回响应,在浏览器输入http://localhost:8089/__admin/可以查看多个请求响应结果

@Test
    void requestMock2() throws InterruptedException {
        WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
        wireMockServer.start();
        configureFor(8089);
        stubFor(get(urlEqualTo("/wirmock/resp"))
                .willReturn(aResponse()
                                .withStatus(200)
                                .withHeader("Content-Type", "text/plain")
                                .withBody("Hello WireMock ResponseMath!")));

        //常见的响应缩写
        stubFor(get("/fine-with-body")
                .willReturn(ok("body content")));

        stubFor(get("/json")
                .willReturn(okJson("{ \"message\": \"Hello\" }")));

        stubFor(get("/annother")
                .willReturn(temporaryRedirect("/new/place")));
        stubFor(get("/new/place")
                .willReturn(okJson("{ \"message\": \"302 local\" }")));

        stubFor(get("/sorry-no")
                .willReturn(unauthorized()));

        stubFor(get("/status-only")
                .willReturn(status(418)));

        sleep(999999);
        WireMock.reset();
        wireMockServer.stop();
    }

  • 多个请求的情况下,可以通过atPriority()方法来设置stub的匹配优先级,数字越小优先级越高
@Test
    void requestMock3() throws InterruptedException {
        WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
        wireMockServer.start();
        configureFor(8089);
        // any - 希望匹配任何请求方法,带参数的请求必须用urlPathEqualTo
        stubFor(get(urlMatching("/api/.*")).atPriority(4)
                .willReturn(aResponse().withStatus(200).withBody("api demo")));

        stubFor(get(urlMatching("/api/resource")).atPriority(1)
                .willReturn(aResponse().withStatus(200).withBody("resource date")));

        stubFor(any(anyUrl()).atPriority(5)
                .willReturn(aResponse().withStatus(401).withBody("mo matching")));

        sleep(999999);
        WireMock.reset();
        wireMockServer.stop();

    }

4.5 实战 - 将WireMock的录制功能写成代码

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;
import org.junit.jupiter.api.Test;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static java.lang.Thread.sleep;

public class ProxyMockTest {
    @Test
    void proxyMock() throws InterruptedException {
        int port =8089;
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig().port(port)
                .extensions(new ResponseTemplateTransformer(true),new ResponseTransformer() {
                    //通过重写transform方法,可以对透传后返回的response进行修改

                    @Override
                    public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
                        String body = response.getBodyAsString();
                        return Response.Builder.like(response)
                                .body(body.replace("Other Utilities","Other Utilities-this is proxy!"))
                                .build();
                    }

                    @Override
                    public String getName() {
                        return "ResponseTransformerDemo";
                    }
                })
        );
        wireMockServer.start();
        configureFor(port);

        //通过proxiedFrom()方法使stub匹配到的请求,可以透传到真正的后端
        stubFor(get(urlMatching(".*"))
                .willReturn(aResponse().proxiedFrom("http://httpbin.ceshiren.com")));

        sleep(999999);
        WireMock.reset();
        wireMockServer.stop();
    }
}

1 Like