You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot单元测试:无需PowerMockito模拟LocalDateTime报错解决

解决SpringBoot单元测试中模拟LocalDateTime的问题

你遇到的MissingMethodInvocationException本质原因是LocalDateTime是final类,且now()是静态方法,Mockito默认无法对这类非mock对象的final/静态方法进行存根(stub),直接在when()里调用LocalDateTime.now()不符合Mockito的使用规则。

下面是三种无需PowerMockito的可行方案:

方案1:封装时间获取逻辑(推荐,符合依赖倒置原则)

把获取当前时间的逻辑封装成可注入的接口,业务代码依赖这个接口而非直接调用LocalDateTime.now(),测试时只需mock这个接口即可。

步骤示例:

  1. 定义时间提供者接口
public interface TimeProvider {
    LocalDateTime getCurrentLocalDateTime();
}
  1. 实现生产环境的时间提供者
@Component
public class DefaultTimeProvider implements TimeProvider {
    @Override
    public LocalDateTime getCurrentLocalDateTime() {
        return LocalDateTime.now();
    }
}
  1. 业务类注入该接口
@Service
public class YourBusinessService {
    private final TimeProvider timeProvider;

    public YourBusinessService(TimeProvider timeProvider) {
        this.timeProvider = timeProvider;
    }

    public LocalDateTime doSomething() {
        // 用接口获取当前时间,而非直接调用LocalDateTime.now()
        LocalDateTime now = timeProvider.getCurrentLocalDateTime();
        // 业务逻辑...
        return now;
    }
}
  1. 单元测试mock TimeProvider
@ExtendWith(MockitoExtension.class)
public class YourBusinessServiceTest {
    @Mock
    private TimeProvider timeProvider;

    @InjectMocks
    private YourBusinessService businessService;

    @Test
    public void testDoSomething() {
        // 模拟固定时间
        LocalDateTime fixedTime = LocalDateTime.of(2024, 5, 20, 10, 30);
        when(timeProvider.getCurrentLocalDateTime()).thenReturn(fixedTime);

        LocalDateTime result = businessService.doSomething();
        assertEquals(fixedTime, result);
    }
}

方案2:使用Mockito Inline Mock Maker(支持mock final类/静态方法)

从Mockito 3.4.0版本开始,提供了inline mock maker,可以直接mock final类和静态方法,无需PowerMockito。

配置步骤:

  1. 在测试资源目录下创建文件:src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
  2. 文件内容仅需一行:
mock-maker-inline
  1. 测试中mock LocalDateTime的静态方法(注意用try-with-resources自动关闭mock)
@ExtendWith(MockitoExtension.class)
public class YourTest {
    @Test
    public void testWithMockedLocalDateTime() {
        LocalDateTime fixedTime = LocalDateTime.of(2024, 5, 20, 10, 30);
        // mock LocalDateTime的静态方法
        try (MockedStatic<LocalDateTime> mockedLocalDateTime = Mockito.mockStatic(LocalDateTime.class)) {
            mockedLocalDateTime.when(LocalDateTime::now).thenReturn(fixedTime);

            // 执行测试逻辑,此时LocalDateTime.now()会返回fixedTime
            LocalDateTime result = LocalDateTime.now();
            assertEquals(fixedTime, result);
        }
    }
}

方案3:修改业务方法,传入时间参数

如果业务逻辑允许,可以将时间作为方法参数传入,测试时直接传入固定时间,完全避免依赖静态方法。

示例:

业务方法修改为:

public LocalDateTime doSomething(LocalDateTime currentTime) {
    // 直接使用传入的时间
    // 业务逻辑...
    return currentTime;
}

测试时直接传固定值:

@Test
public void testDoSomething() {
    LocalDateTime fixedTime = LocalDateTime.of(2024, 5, 20, 10, 30);
    LocalDateTime result = businessService.doSomething(fixedTime);
    assertEquals(fixedTime, result);
}

内容的提问来源于stack exchange,提问作者NNFdo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:36:00