3、常见Mock工具介绍:Mockito、EasyMock、WireMock、MockServer使用场景
做Mock回放性能测试,第一步就是选对工具。市面上的Mock工具不少,但真正经得起实战考验的就那么几个。我这些年用过不下十种Mock框架,踩过的坑能写本书。今天拎出四个最主流的——Mockito、EasyMock、WireMock、MockServer,聊聊它们到底该用在什么场景,以及我个人的一些取舍。
先画个全景图,方便你建立整体认知:
3.1 Mockito – 单元测试的标配
如果让我只选一个Mock框架,我选Mockito。这玩意儿现在几乎是Java项目单元测试的标配。我的个人习惯是:只要写单元测试需要隔离依赖,第一反应就是Mockito。
核心能力:基于动态代理,对接口和类进行mock、stub、verify。配合JUnit4/5使用非常丝滑。
举个最简单的例子:
// 模拟一个UserService
UserService mockService = mock(UserService.class);
when(mockService.getUserName(1)).thenReturn("张三");
// 调用测试逻辑
String name = mockService.getUserName(1);
assertEquals("张三", name);
// 验证调用次数
verify(mockService, times(1)).getUserName(1);
使用场景:
- 单元测试中被依赖对象的隔离(DAO、远程服务代理、事件总线等)
- 需要验证方法调用次数、参数匹配
- 简单的返回值或者异常抛出模拟
经验之谈:我记得有一次在压测一个批量数据处理模块时,发现单元测试跑得极慢。一查,原来整个测试类里用了大量的mock对象,但每次都是new出来的,没做复用。后来改成@Mock + @InjectMocks,配合@RunWith(MockitoJUnitRunner.class),速度提升了好几倍。
避坑指南:我曾经被Mockito的spy坑过——用spy(realObj)去部分mock真实对象时,如果对象里有final方法或私有方法,会直接抛异常。记住,Mockito对final、static、private的支持非常有限,需要额外配mockito-inline或使用PowerMock。实测中,混合使用容易导致测试不稳定。
性能表现:Mockito的mock创建成本大约几十微秒级别,对于几千个mock对象的测试来说几乎不构成瓶颈。但要注意:千万不要在循环里反复创建mock对象,尤其是性能测试场景下。
3.2 EasyMock – 老牌可靠,但已退流行
EasyMock比Mockito出现得更早,很多遗留项目还在用它。说实话,除了惯性依恋,现在的场景下我不太推荐新项目入坑EasyMock。
核心能力:也是动态代理mock,语法上采用录制-回放模式。先录制期望行为,再切换到replay模式,最后verify。
代码示例:
UserService mockService = EasyMock.createMock(UserService.class);
// 录制阶段
expect(mockService.getUserName(1)).andReturn("李四");
EasyMock.replay(mockService);
// 测试
String name = mockService.getUserName(1);
assertEquals("李四", name);
// 验证
EasyMock.verify(mockService);
使用场景:
- 维护老项目,团队已经习惯了EasyMock语法
- 对strict mock有严格顺序要求的场景(EasyMock支持Strict Mock)
- 需要mock类且对final方法有操作(EasyMock可以扩展支持,但不如PowerMock方便)
我个人建议:如果你是新项目,直接上Mockito。EasyMock的录制-回放模式在复杂场景下很难维护,尤其是当测试方法里有很多mock时。我在一个支付核心项目的重构中,硬是把200多个EasyMock测试改成了Mockito,最终可读性提升明显。
性能表现:与Mockito相当。但EasyMock的strict mock模式启动时校验较多,会稍微慢一点。在性能测试场景下,不建议使用strict mock。
3.3 WireMock – HTTP服务模拟利器
单元测试之外,我们经常要模拟外部的HTTP服务——比如支付网关、短信接口、第三方API。这时候WireMock就登场了。
核心能力:启动一个嵌入式的HTTP服务器,可以配置stub映射、延迟注入、请求验证、录制回放。
基础用法:
// 启动WireMock
WireMockServer wireMockServer = new WireMockServer(options().port(8089));
wireMockServer.start();
// 配置stub:GET /api/user/1 返回固定JSON
stubFor(get(urlEqualTo("/api/user/1"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("{ \"name\": \"王五\" }")));
// 发起请求(用你的HTTP客户端)
String result = httpClient.get("http://localhost:8089/api/user/1");
// 验证请求是否被调用
verify(getRequestedFor(urlEqualTo("/api/user/1")));
使用场景:
- 集成测试中模拟外部HTTP服务
- 性能测试中模拟第三方依赖的响应(延迟、错误码等)
- 录制真实服务的请求/响应,用于回放测试
我遇到的典型场景:有一次做电商的订单压力测试,外围有10多个第三方接口(支付、物流、短信)。如果每次压测都调真实接口,成本高不说,还容易把第三方打爆。我们用WireMock录制了这些接口的真实响应,然后在压测集群里部署WireMock实例,给每个服务配置延迟和错误注入。最后压测跑了几个小时,第三方那边基本没收到真实请求——舒服。
避坑指南:WireMock的录制功能生成的mapping文件会把请求URL、Header、Body全量匹配,有时候会造成匹配失败。我踩过一坑:录制时没注意Content-Type包含charset,回放时请求少了一个分号,结果一直返回404。最后的解决方法是:在stub匹配规则里用urlPathEqualTo()代替urlEqualTo(),忽略query参数。
性能表现:单机WireMock的吞吐量大约在每秒几千到上万请求,具体取决于stub数量。在性能测试中,如果作为回放服务器,建议用JVM调优,增大堆内存,并关闭不必要的日志。
3.4 MockServer – 更强大的服务模拟平台
如果说WireMock是轻巧的步枪,那么MockServer更像是重武器。
核心能力:支持HTTP/HTTPS、WebSocket、SOCKS等协议,可录制、可回放、可断言。提供REST API管理mock内容,支持动态响应基于JavaScript模板。
示例(通过API创建expectation):
// 创建MockServer客户端
MockServerClient client = new MockServerClient("127.0.0.1", 1090);
client.when(
request().withMethod("POST").withPath("/order"),
Times.exactly(1)
).respond(
response()
.withStatusCode(200)
.withBody("{\"orderId\":\"123456\"}")
.withDelay(TimeUnit.MILLISECONDS, 200)
);
使用场景:
- 需要支持多个协议的mock(比如同时模拟HTTP和WebSocket)
- 需要持久化录制数据,支持长期回放测试
- 需要动态生成响应(比如根据请求参数不同返回不同内容)
- 团队需要统一的mock管理平台(MockServer提供控制台UI)
我个人偏好:MockServer的学习曲线比WireMock陡一些,但一旦你在性能测试中需要模拟复杂的业务逻辑(比如下单成功后异步回调),MockServer的JavaScript模板能省你很多事。我在几个大型金融项目的全链路压测中都用它做核心回放介质。
性能表现:MockServer的吞吐量略低于WireMock(因为支持更多特性),但通过配置连接池和线程池,也能达到每秒数千请求。如果作为回放中心,一定要控制录制的会话数量,否则JVM内存容易飙升。
工具选择速查表
| 对比维度 | Mockito | EasyMock | WireMock | MockServer |
|---|---|---|---|---|
| 主要用途 | 单元测试依赖隔离 | 单元测试(老项目) | HTTP服务模拟 | 多协议服务模拟 |
| 协议支持 | Java方法调用 | Java方法调用 | HTTP/HTTPS | HTTP/HTTPS/WebSocket/SOCKS |
| 录制回放 | 不支持 | 不支持 | 支持(基础) | 支持(丰富) |
| 扩展能力 | 低(需配合PowerMock) | 低 | 中(可自定义匹配器) | 高(JS模板、REST API) |
| 性能表现 | 极高(微秒级) | 高(微秒级) | 高(毫秒级) | 中(毫秒级,稍慢) |
| 推荐指数(🌟) | ★★★★★ | ★★☆☆☆ | ★★★★☆ | ★★★☆☆ |
小结:选哪个工具,本质上取决于你的测试层级。单元测试无脑上Mockito;需要模拟HTTP服务时,轻量场景用WireMock,复杂场景用MockServer。EasyMock?嗯,除非你不得不维护老代码,否则就别回头看了。