1. 概述
在单元测试中,我们常常会使用 Mock 框架 来模拟依赖对象的行为,从而实现对当前类的隔离测试。通常我们会模拟依赖对象的返回值,以验证被测类在不同返回值下的行为是否正确。
但有时候我们也会遇到一些依赖方法是 void 类型 的,这类方法没有返回值,却可能有副作用(如修改入参、抛出异常等)。此时我们也需要模拟这些行为。
本文将介绍 如何使用 EasyMock 来模拟 void 方法,包括模拟异常抛出、模拟副作用等常见场景。
2. Maven 依赖
在使用 EasyMock 前,需要先在 pom.xml
中引入依赖:
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>4.0.2</version>
<scope>test</scope>
</dependency>
3. 什么时候需要模拟 Void 方法
虽然 void 方法没有返回值,但它可能会产生副作用,比如:
- 修改传入参数的状态
- 抛出异常
- 触发某些异步行为
比如经典的 Session.save()
方法,虽然返回值为 void,但在保存实体时会为其生成 ID 并设置回传入的对象。
✅ 模拟 void 方法的常见场景:
- 验证被测类是否能正确处理 void 方法抛出的异常
- 模拟 void 方法对参数的修改,以验证后续逻辑是否正确
4. 如何模拟 Void 方法
我们以一个 WeatherService
接口为例,其中有一个 void 方法 populateTemperature()
:
public interface WeatherService {
void populateTemperature(Location location);
}
4.1. 创建 Mock 对象
使用 EasyMock 提供的 @Mock
注解创建 mock 对象:
@Mock
private WeatherService mockWeatherService;
也可以使用静态方法创建:
WeatherService mockWeatherService = EasyMock.mock(WeatherService.class);
接着记录期望调用的方法:
mockWeatherService.populateTemperature(EasyMock.anyObject(Location.class));
如果只是模拟 void 方法被调用而无需模拟具体行为,这样就足够了。
4.2. 模拟抛出异常
如果要测试异常处理逻辑,可以使用 andThrow()
方法模拟异常抛出:
EasyMock.expectLastCall().andThrow(new ServiceUnavailableException());
⚠️ 注意:expectLastCall()
是关键,它表示对上一次调用的方法设置预期行为。
4.3. 模拟方法行为
若希望 void 方法修改入参对象,比如填充温度值,可以使用 andAnswer()
方法:
EasyMock.expectLastCall()
.andAnswer(() -> {
Location passedLocation = (Location) EasyMock.getCurrentArguments()[0];
passedLocation.setMaximumTemperature(new BigDecimal(MAX_TEMP));
passedLocation.setMinimumTemperature(new BigDecimal(MAX_TEMP - 10));
return null; // void 方法必须返回 null
});
✅ 技巧说明:
EasyMock.getCurrentArguments()
获取调用时传入的参数- 修改参数对象的状态,模拟真实方法的副作用
- 返回值为
null
是因为方法本身没有返回值
⚠️ 注意:andAnswer()
不仅适用于 void 方法,也适用于需要根据参数动态返回值的场景。
4.4. 回放 Mock 对象
最后调用 replay()
方法切换 mock 对象为回放模式:
EasyMock.replay(mockWeatherService);
此时,当被测类调用 populateTemperature()
方法时,就会执行我们模拟的行为。
5. 总结
本文介绍了如何使用 EasyMock 模拟 void 方法的常见场景,包括:
✅ 模拟 void 方法被调用
✅ 模拟 void 方法抛出异常
✅ 模拟 void 方法修改参数对象状态
掌握了这些技巧后,就可以更灵活地进行单元测试,特别是在处理复杂依赖时非常有用。
完整的示例代码可参考:GitHub 仓库