WireMock初体验,一个强大的HTTP 请求模拟测试框架

本文介绍如何使用WireMock框架改进HTTP请求的单元测试,通过打桩技术模拟HTTP响应,确保测试的独立性和准确性。文章详细展示了WireMock的配置和使用示例,以及其在真实项目测试中的强大功能。

缘起

最近我创建并维护了一个开源项目 http-api-invoker ,该项目实现将 HTTP 请求和接口进行绑定,让 HTTP 接口调用跟调用本地方法一样自然优雅。在写单元测试的时候,因为需要发送 HTTP 请求,而做为一个完整独立的项目,我并不希望对它进行单测还需要依赖其他的项目。最开始我用的是 Mockito。

为了让代码更易于测试,我将真正发送请求的任务交给一个接口(Requestor),然后写了一个默认的实现类,用于发送请求。当需要测试的时候,Mock一个Requestor,于是所有请求并没有真正地发出去,只需要断言这个Mock出来的Requstor发送请求的方法有没有被正确调用就可以。

这个是使用 Mockito 的情况下,我能想到的最好的解决方案了。

但是,这里面有一个问题。默认的 Requestor 实现又如何被独立测试呢? 这让我犯难了,所以项目刚开始的时候并没有对默认的 Requestor 进行单元测试,也没有测试真正发送请求的情况下,代码的逻辑是否正确。

偶遇

不久前的某个深夜,我偶然间看到一篇 InfoQ 的上的文章 Stubbing, Mocking and Service Virtualization Differences for Test and Development Teams 让我充分了解了Mock、打桩和模拟服务的区别和应用场景,受益匪浅。在文章里面介绍了 wiremock 这个框架,于是我找到官网 ,看了一下,文档非常地清晰和完善。感觉如获至宝。

应用

我的项目刚好最需要这样的框架来做单元测试。于是我动手写了测试样例。因为官网有非常详细的文档,而且也查看了一些博客上的入门样例,很快就上手了。深深感觉到它的强大,真的非常振奋人心。具体代码可以查看 CityServiceTest 这个测试类。

使用入门

引入 maven 依赖

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-standalone</artifactId>
    <version>2.19.0</version>
    <scope>test</scope>
</dependency>

使用入门示例

我这里写了一个简单的测试用例,完整的真实项目用例可以查看 CityServiceTest

public class HelloWireMockTest {
    private static final int PORT = 18888;
    /**
     * 使用给定的端口号生成WireMockRule实例.
     * 这里设置之后,启动测试时 WireMock 会使用内嵌的 Jetty 启动一个 Web 服务器并监听指定的端口
     */
    @Rule
    public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
    
    @Test
    public void helloTest() {
        String uri = "/say/hello";
        String body = "Hello World!";
        // 给uri打桩,这个语句表示,拦截 uri 为 /say/hello 的请求回复 "Hello World!"
        wireMockRule.stubFor(get(urlEqualTo(uri))
        			   .willReturn(aResponse().withBody(body)));
        // 这里我们可以用任何方式发起HTTP的GET请求
        String result = HttpUtil.get("http://localhost:" + PORT + uri);
        System.out.println(result);
        // 断言我们发出的请求返回了我们期望的结果
        assertEquals(result, body);
    }

这个测试用例跑起来的时候,WireMock会启动一个Web服务器监听 18888 端口,然后我们预设 /say/hello 接口将返回 Hello World! 这行文本做为响应,接下来我们发一个请求过去,断言拿到的是我们期望的结果。

更强大的是,当发的请求跟我们预设的不匹配的时候,它会明明白白地告诉我们,差异在哪里,例如:
请求与预设不匹配

而且它也支持 header 和 cookie 的验证,例如

    @Test
    public void getCityWithHeaders() {
        Map<String, String> headers = new HashMap<>();
        String key = "auth";
        String key2 = "auth2";
        headers.put(key, "123");
        headers.put(key2, "321");
        int id = 1;
        String uri = "/city/getCityRest/" + id;
        City mockCity = createCity(id);
        wireMockRule.stubFor(get(urlEqualTo(uri))
                // 声明我们的请求必须包含两个指定的 header  
                .withHeader(key, equalTo(headers.get(key)))
                .withHeader(key2, equalTo(headers.get(key2)))
                // 一旦有符合要求的请求过来,则返回指定的响应
                .willReturn(aResponse().withBody(JSON.toJSONString(mockCity))));
        // 使用 http-api-invoker 框架,只需调用接口的方法,框架会发送相应的 http 请求
        // 这里 cityService.getCityWithHeaders 方法我们绑定的地址是 /getCityRest/{id}
        City result = cityService.getCityWithHeaders(id, headers);
        assertEquals(mockCity, result);
    }

如果我们发请求的时候,header 没有带上,那么控制台就会打印出下面这报告:
请求缺少必要的Header

结语

单元测试对于写出健壮且高质量的代码非常有必要。没有单测,开发的时候就像夜里一个人走在没有灯的荒郊野岭,你永远不知道前面等待你的是小坑还是深渊,有时候出了问题自己怎么死的都不知道。而单元测试为这场野外旅行添置了一盏明灯,照亮前面的路,让你每走几步都能知道现在处在什么位置。就算掉坑里,也马上让你知道你现在在坑里,赶紧出来,以防止更糟糕的情况。

一个好的单元测试用例也有很大的学问,我相信,花一些时间学习和了解这些技能是一本万利的事情。与君共勉。

### WireMock 安装步骤 WireMock一个功能强大模拟服务器工具,广泛用于测试和开发环境中模拟 HTTP 服务。以下是安装 WireMock 的主要步骤: 1. **通过 Maven 安装依赖** 如果使用 Java 和 Maven 项目,可以通过在 `pom.xml` 文件中添加 WireMock 依赖来集成。以下是一个典型的配置示例: ```xml <properties> <wiremock.version>2.27.2</wiremock.version> </properties> <dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock</artifactId> <version>${wiremock.version}</version> <scope>test</scope> </dependency> ``` 这将确保 WireMock 被正确引入项目中,并在测试范围内可用[^1]。 2. **通过独立 JAR 文件安装** WireMock 提供了独立的 JAR 文件,可以快速启动模拟服务器。首先,从 [WireMock 官方网站](http://wiremock.org/) 下载 JAR 文件。然后,运行以下命令: ```bash java -jar wiremock-standalone-2.27.2.jar --port 8081 ``` 这将启动 WireMock 服务器,并监听 8081 端口[^1]。 3. **通过 Docker 安装** 如果使用 Docker,可以直接拉取 WireMock 的镜像并运行。以下是运行 WireMock Docker 容器的示例命令: ```bash docker run -d -p 8081:8081 wiremock/wiremock ``` 这将启动一个 WireMock 实例,并监听 8081 端口。 ### WireMock 部署方法 部署 WireMock 可以采用多种方式,具体取决于使用场景和需求: 1. **本地测试环境部署** 在本地开发环境中,可以使用 Java 代码启动 WireMock 服务器。例如: ```java import com.github.tomakehurst.wiremock.WireMockServer; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; public class WireMockExample { public static void main(String[] args) { WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8081)); wireMockServer.start(); } } ``` 这段代码将启动一个 WireMock 服务器,监听 8081 端口[^2]。 2. **远程服务器部署** WireMock 可以部署在远程服务器上,以便多个开发人员或测试环境共享。这通常通过将 WireMock 作为独立服务运行来实现。例如,使用 JAR 文件或 Docker 容器在远程服务器上启动 WireMock。 3. **集成到 CI/CD 流程** WireMock 可以集成到 CI/CD 流程中,用于自动化测试。例如,在 Jenkins 或 GitHub Actions 中,可以配置任务以启动 WireMock 服务器并运行测试。 4. **Kubernetes 部署** 如果使用 Kubernetes,可以通过 Helm Chart 或 Kubernetes 配置文件部署 WireMock。例如,使用 Helm 安装 WireMock: ```bash helm repo add wiremock https://wiremock.github.io/wiremock-helm-chart/ helm install wiremock wiremock/wiremock ``` 这将部署 WireMock 到 Kubernetes 集群中[^3]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值