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

如何使用Mockito模拟Supplier<UUID>类型的Spring Bean?

问题:Mockito无法模拟Supplier类型的Spring Bean(Cucumber测试场景)

原Bean定义

@Bean("idGenerator")
public Supplier<UUID> idGenerator() {
  return () -> UUID.randomUUID();
}

问题现象

在SpringBootTest类中使用@MockBean尝试模拟上述Bean时触发错误,提示无法模拟该类(疑似JVM限制)。后续补充栈信息后确认:标准单元测试场景下可正常运行,问题仅出现在cucumber-java测试中。

临时方案(未被认可)

曾尝试在@TestConfiguration中新增字段,允许外部指定Supplier的返回值,但该方案不够优雅,未得到认可。

补充的栈信息(已翻译)

Before All/After All 执行失败
io.cucumber.core.exception.CompositeCucumberException: 共出现15个异常,详情见下方栈跟踪
    at io.cucumber.core.runtime.RethrowingThrowableCollector.getThrowable(RethrowingThrowableCollector.java:57)
    at io.cucumber.core.runtime.CucumberExecutionContext.getThrowable(CucumberExecutionContext.java:102)
    at io.cucumber.core.runtime.CucumberExecutionContext.finishTestRun(CucumberExecutionContext.java:97)
    at io.cucumber.core.runtime.Runtime.execute(Runtime.java:96)
    at io.cucumber.core.runtime.Runtime.run(Runtime.java:87)
    at io.cucumber.core.cli.Main.run(Main.java:87)
    at io.cucumber.core.cli.Main.main(Main.java:30)
    被抑制异常: java.lang.IllegalStateException: 加载ApplicationContext失败
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)
        at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
        at io.cucumber.spring.TestContextAdaptor.<init>(TestContextAdaptor.java:32)
        at io.cucumber.spring.SpringFactory.start(SpringFactory.java:120)
        at io.cucumber.core.runner.Runner.buildBackendWorlds(Runner.java:134)
[...]
    根因: org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名为[...]的Bean失败: 构造器参数5存在不满足的依赖;
    嵌套异常为 org.mockito.exceptions.base.MockitoException: 
无法模拟/监视类 BackendApplicationConfiguration$$Lambda$1713/0x00000008018fd980
Mockito无法模拟/监视的原因:
 - VM不支持修改指定类型
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)

解决方案

方案1:修改原Bean定义(推荐)

将Lambda表达式替换为匿名内部类,避免生成JVM无法修改的Lambda动态类,让Mockito可以正常模拟:

@Bean("idGenerator")
public Supplier<UUID> idGenerator() {
    return new Supplier<UUID>() {
        @Override
        public UUID get() {
            return UUID.randomUUID();
        }
    };
}

修改后,@MockBean即可正常工作:

@SpringBootTest
public class YourCucumberSteps {
    @MockBean(name = "idGenerator")
    private Supplier<UUID> mockIdGenerator;

    // 测试步骤中设置预期
    @Given("生成指定UUID")
    public void setupMockUuid() {
        UUID fixedUuid = UUID.fromString("d290f1ee-6c54-4b01-90e6-d701748f0851");
        Mockito.when(mockIdGenerator.get()).thenReturn(fixedUuid);
    }
}

方案2:通过TestConfiguration替换Bean(不修改原代码)

如果无法修改原Bean定义,可通过自定义测试配置替换原Bean,并管理mock对象:

@TestConfiguration
public class IdGeneratorTestConfig {
    private final Supplier<UUID> mockSupplier = Mockito.mock(Supplier.class);

    @Bean("idGenerator")
    @Primary // 确保优先使用该Bean替换原Bean
    public Supplier<UUID> idGenerator() {
        return mockSupplier;
    }

    public Supplier<UUID> getMockSupplier() {
        return mockSupplier;
    }
}

在Cucumber步骤类中注入配置类,获取mock对象设置预期:

@SpringBootTest(classes = {YourApplication.class, IdGeneratorTestConfig.class})
public class YourCucumberSteps {
    @Autowired
    private IdGeneratorTestConfig testConfig;

    @Given("mock UUID生成器返回 {string}")
    public void mockUuidGenerator(String uuidStr) {
        UUID mockUuid = UUID.fromString(uuidStr);
        Mockito.when(testConfig.getMockSupplier().get()).thenReturn(mockUuid);
    }
}

原因分析

栈信息显示Mockito尝试模拟的是一个Lambda动态生成类(BackendApplicationConfiguration$$Lambda$1713/0x00000008018fd980),JVM对这类动态生成的Lambda类有修改限制,Mockito默认无法模拟。而Cucumber的Spring集成在加载上下文时,直接将原Bean的Lambda实例作为替换目标,而非Supplier接口本身,导致模拟失败;标准单元测试场景下Spring的处理逻辑不同,因此可以正常运行。

内容的提问来源于stack exchange,提问作者Mr. Gung

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:10:30