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 仓库


原始标题:Mocking a Void Method with EasyMock