不使用PowerMock如何mock UUID.randomUuid()和System.currentTimeMillis()?
不用PowerMock实现
UUID.randomUUID()和System.currentTimeMillis()Mock的方案 方案1:依赖注入封装(最推荐)
通过封装系统静态方法为可注入的接口,从架构层面解决静态方法不可测的问题,完全不需要特殊Mock能力,Sonar兼容性最好:
- 第一步:封装两个方法对应的Provider接口与默认实现
// UUID生成能力封装 public interface UuidProvider { UUID generate(); } // 生产环境默认实现 public class DefaultUuidProvider implements UuidProvider { @Override public UUID generate() { return UUID.randomUUID(); } }
// 系统时间获取能力封装 public interface CurrentTimeProvider { long currentTimeMillis(); } // 生产环境默认实现 public class DefaultCurrentTimeProvider implements CurrentTimeProvider { @Override public long currentTimeMillis() { return System.currentTimeMillis(); } }
- 第二步:业务代码中替换直接调用静态方法的逻辑,注入对应Provider实例使用,Spring等框架可直接将默认实现注册为单例Bean。
- 第三步:单元测试时直接Mock接口即可,用普通Mockito框架就能实现,不需要任何静态Mock能力:
// 测试Mock示例 UuidProvider mockUuidProvider = Mockito.mock(UuidProvider.class); Mockito.when(mockUuidProvider.generate()).thenReturn(UUID.fromString("123e4567-e89b-12d3-a456-426614174000")); CurrentTimeProvider mockTimeProvider = Mockito.mock(CurrentTimeProvider.class); Mockito.when(mockTimeProvider.currentTimeMillis()).thenReturn(1690000000000L);
方案2:使用Mockito 3.4+内置静态Mock能力
如果不想修改现有代码结构,可以使用Mockito 3.4及以上版本自带的静态Mock能力,完全替代PowerMock的静态Mock功能,Sonar兼容性远高于PowerMock:
- 依赖替换:将项目中的
mockito-core依赖替换为mockito-inline即可开启静态Mock能力。 - 测试代码写法:
// Mock UUID.randomUUID()示例 try (MockedStatic<UUID> mockedUuid = Mockito.mockStatic(UUID.class)) { mockedUuid.when(UUID::randomUUID).thenReturn(UUID.fromString("123e4567-e89b-12d3-a456-426614174000")); // 执行业务逻辑代码 yourBusinessMethod(); } // Mock System.currentTimeMillis()示例 try (MockedStatic<System> mockedSystem = Mockito.mockStatic(System.class)) { mockedSystem.when(System::currentTimeMillis).thenReturn(1690000000000L); // 执行业务逻辑代码 yourBusinessMethod(); }
注意:静态Mock必须放在try-with-resources代码块中使用,执行完成后会自动释放Mock,避免影响其他测试用例的运行。
选型建议
优先选择第一种封装方案,符合依赖倒置设计原则,代码可测试性、可维护性更高,不存在任何测试框架兼容性问题,也不会影响Sonar的覆盖率统计结果。
内容的提问来源于stack exchange,提问作者user16976904
相关产品推荐
相关产品推荐

