当前位置:   article > 正文

Mock技术的深度理解及WireMock框架基础使用

wiremock

一、关键概念

  1. spy:主要是监听调用过程,不具备转发能力(类似抓包,F12的功能)
  2. stub:返回固定值的实现,无法在测试中进行动态变更(指无法根据真实的值进行动态变更),比较死板(类似Charles的map local功能,不经过后端,类似挡板)
  3. proxy:使用代理协议转发请求并返回真实内容,可以转发、监听,甚至修改(类似Charles的rewrite功能,把请求转发给真实的服务,服务返回response后,对response进行一些修改后转发给前端)
  4. fake:用假的实现代替真的实现,但是实现中做了些捷径(比如一个大集群下某个服务出故障,需要很长时间去修复,这个时候可以写一个简版的逻辑进行替代,通常是开发做的)
  5. mock:由mock库动态创建的,能提供类似spy、stub、proxy的功能。mock是一种特殊的fake,强调的是可控
  • mock on stub:直接返回固定值数据
  • mock on proxy:利用代理转发并修改返回数据

在这里插入图片描述

二、应用场景

一、stub应用场景:Moco

  • https://github.com/dreamhead/moco
  • 轻量级stub框架,用命令行进行启动,方便在服务端操作

二、fake应用场景:H2 Database Engine

  • 轻量级的内存Sql,不会占用资源,是JDBC的api,操作方式和mysql之类的一致。如果是试运行阶段或者重点关注重点不在db层,可以使用这个框架。

三、mock应用场景:Wire Mock

  • 目前一款较为流行的mock框架,社区很活跃,写法也很优雅,功能和Charles差不多,但是更灵活,因为可以进行编码
  • 官网:http://wiremock.org/
  • 下面我们重点介绍下这款框架的基础配置和使用
1. 引入依赖
  <groupId>org.example</groupId>
    <artifactId>wiremock_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-console-standalone</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.tomakehurst</groupId>
            <artifactId>wiremock-jre8</artifactId>
            <version>2.31.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.lightbody.bmp</groupId>
            <artifactId>browsermob-core</artifactId>
            <version>2.1.5</version>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                    <includes>
                        <include>**</include>
                    </includes>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>
        </plugins>
    </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
2. 演示
1、基础demo
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
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 Demo_01_Base {
    @Test
    public void start() {
        int port = 8089;
        // 实例化wirmockServer对象
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig()
                        // 配置端口号
                        .port(port)
                        // 配置全局response模板
                        .extensions(new ResponseTemplateTransformer(true))
        );
        // 启动mock服务
        wireMockServer.start();
        // 这边需要再次设置一下端口号,否则会报错
        configureFor(port);
        // 配置mock服务中的一个stub,类似Charles的mapLocal功能
        stubFor(get(urlEqualTo("/some/thing"))
                // 配置返回的body,header,statusCode
                .willReturn(
                        aResponse()
                                .withStatus(200)
                                .withHeader("content-Type", "application/json")
                                .withBody("this is my first wiremock demo!")
                ));
        System.out.println("http://localhost:" + port);
        // 等待10s,如果不等待就会直接停止服务,就启动不了了
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // wiremock复位
        WireMock.reset();
        // wiremock停止(不停止下一次就无法进行调用了)
        wireMockServer.stop();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 启动并访问
    在这里插入图片描述
2、常用的请求体的配置
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
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 Demo_02_RequestMatching {
    @Test
    public void start() {
        int port = 8090;
        // 实例化wirmockServer对象
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig()
                        // 配置端口号
                        .port(port)
                        // 配置全局response模板
                        .extensions(new ResponseTemplateTransformer(true))
        );
        // 启动mock服务
        wireMockServer.start();
        // 这边需要再次设置一下端口号,否则会报错
        configureFor(port);
        /**
         *   配置mock服务中的一个stub,类似Charles的mapLocal功能
         *   这些配置是“且”的关系,必须全部满足,才能请求成功
         */

        // url的路径等于"everything"’
        stubFor(any(urlPathEqualTo("everything"))
                //通过header匹配规则
                .withHeader("Accept", containing("xml"))
                //通过cookie匹配规则
                .withCookie("session", matching(".*12345.*"))
                //通过QueryParam匹配规则
                .withQueryParam("search_term", equalTo("WireMock"))
                //通过withBasicAuth匹配规则
                .withBasicAuth("jeff@example.com", "jeffteenjefftyjeff")
                //通过RequestBody匹配规则
                .withRequestBody(matchingJsonPath("$.a", equalTo("1")))
                .willReturn(aResponse().withStatus(200)
                        .withHeader("Content-Type", "text/plain")
                        .withBody("pass!")));
        System.out.println("http://localhost:" + port);
        // 等待10s,如果不等待就会直接停止服务,就启动不了了
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // wiremock复位
        WireMock.reset();
        // wiremock停止(不停止下一次就无法进行调用了)
        wireMockServer.stop();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 启动并访问
    在这里插入图片描述

  • 做个测试

public class Demo_02_Test_RequestMatching {
    @Test
    void testRequestMatching() {
        given().log().all()
                .auth().preemptive().basic("jeff@example.com", "jeffteenjefftyjeff")
                .header("Accept", "xml")
                .cookie("session", "123456")
                .body("{\"a\":1,\"b\":2}")
                .queryParam("search_term", "WireMock")
                .when()
                .post("http://localhost:8099/everything").
                then().log().all()
                .extract();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

请求成功!
在这里插入图片描述

  • 查看wireMock的管理后台:ip:port/__admin
    在这里插入图片描述
3、常用的响应体的配置
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
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 Demo_03_Response {
    @Test
    public void start() {
        int port = 8091;
        // 实例化wirmockServer对象
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig()
                        .port(port)
                        .extensions(new ResponseTemplateTransformer(true))
        );
        // 启动mock服务
        wireMockServer.start();
        configureFor(port);
        stubFor(get(urlEqualTo("/some/thing"))
                // 配置返回的body,header,statusCode
                .willReturn(
                        aResponse()
                                .withStatus(200)
                                .withHeader("content-Type", "application/json")
                                .withBody("this is my first wiremock demo!")
                ));
        // ok()表示返回响应状态码为200
        stubFor(delete("/fine")
                .willReturn(ok()));
        // 返回响应状态码+body
        stubFor(get("/fineWithBody")
                .willReturn(ok("body")));
        // 返回响应体为json格式
        stubFor(get("/returnJson")
                .willReturn(okJson("{\"status\":\"success\"}")));
        // 进行请求重定向
        stubFor(get("/redirect")
                .willReturn(temporaryRedirect("/new/place")));
        // 未鉴权
        stubFor(get("/unauthorized")
                .willReturn(unauthorized()));
        // 配置响应状态码
        stubFor(get("/statusCode")
                .willReturn(status(418)));

        System.out.println("http://localhost:" + port);
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // wiremock复位
        WireMock.reset();
        // wiremock停止(不停止下一次就无法进行调用了)
        wireMockServer.stop();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 启动
    在这里插入图片描述
    /reidrect 请求重定向
    在这里插入图片描述
4、匹配优先级
/**
 * 优先级匹配:
 * 1,匹配优先级高的
 * 2,再按照url进行匹配
 */
public class Demo_04_Priority {
    @Test
    public void start() {
        int port = 8093;
        // 实例化wirmockServer对象
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig()
                        .port(port)
                        .extensions(new ResponseTemplateTransformer(true))
        );
        // 启动mock服务
        wireMockServer.start();
        configureFor(port);
        // 匹配特定的
        stubFor(get(urlEqualTo("/some/thing")).atPriority(2)
                // 配置返回的body,header,statusCode
                .willReturn(
                        aResponse()
                                .withStatus(200)
                                .withHeader("content-Type", "application/json")
                                .withBody("this is my first wiremock demo!")
                ));
        // 使用正则进行通配
        stubFor(get(urlMatching("/some/.*")).atPriority(12)
                .willReturn(
                        aResponse()
                                .withStatus(401)
                                .withBody("match any")
                ));
        // 兜底逻辑
        stubFor(any(anyUrl()).atPriority(15)
                .willReturn(
                        aResponse()
                                .withStatus(402)
                                .withBody("no match")
                ));
        System.out.println("http://localhost:" + port);
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // wiremock复位
        WireMock.reset();
        // wiremock停止(不停止下一次就无法进行调用了)
        wireMockServer.stop();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 启动
  • 完整匹配
    在这里插入图片描述
  • 匹配部分
    在这里插入图片描述
  • 兜底逻辑
    在这里插入图片描述
5、录制和回放

wireMock也提供界面,进行录制和回放,功能类似于Charles里面的save response

  • 具体操作:
  1. 输入网址:http://ip:port/__admin/recorder/
  2. 在这个界面输入你想要录制的网址,然后点击录制选项
  3. 新开一个页面,输入http://ip:port,会自动路由到你输入的网址,这个时候你可以在页面进行一些操作
  4. ps:跑之前切记一定要去resources文件夹里新建mappings文件夹!!否则是无法进行录制的!!我找了好久才找到这个原因!!
    在这里插入图片描述
  5. 点击stop停止录制
    在这里插入图片描述
    这个时候你会在resources目录里面看到mappings文件,里面放着录制好的请求
    在这里插入图片描述
  6. 我们可以修改里面的内容
    在这里插入图片描述
  7. 然后再进行重启,再去访问http://ip:port,即可mock成功
    在这里插入图片描述
6、 proxy:使用代理协议转发请求并返回真实内容
/**
 * 使用代理协议转发请求并返回真实内容
 */
public class Demo_05_Proxy {
    @Test
    public void start() {
        int port = 8021;
        // 实例化wirmockServer对象
        WireMockServer wireMockServer = new WireMockServer(
                wireMockConfig()
                        // 配置端口号
                        .port(port)
                        // 配置全局response模板
                        .extensions(new ResponseTemplateTransformer(true),
                                // 新建一个response的处理器
                                new ResponseTransformer() {
                                    // 对response里的文本进行替换
                                    @Override
                                    public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
                                        return Response.Builder.like(response)
                                                .body(response.getBodyAsString().replace("Other Utilities","My proxy Utilities"))
                                                .build();
                                    }

                                    @Override
                                    public String getName() {
                                        return "proxy demo";
                                    }
                                })
        );
        // 启动mock服务
        wireMockServer.start();
        configureFor(port);
        // 配置mock服务中的一个stub
        stubFor(get(urlMatching("/.*"))
                .willReturn(
                        aResponse()
                                // 设置代理
                                .proxiedFrom("https://httpbin.ceshiren.com")
                ));
        System.out.println("http://localhost:" + port);
        try {
            Thread.sleep(10000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // wiremock复位
        WireMock.reset();
        // wiremock停止(不停止下一次就无法进行调用了)
        wireMockServer.stop();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 启动以后,访问ip:port,修改成功!
    在这里插入图片描述
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/217014
推荐阅读
相关标签
  

闽ICP备14008679号