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

SpringBoot 3.4.0中@MockBeans弃用后的批量Mock替代方案咨询

解决Spring Boot 3.4.0中批量Mock服务的方案

针对Spring Boot 3.4.0弃用@MockBean/@MockBeans后,无法批量Mock多个服务的问题,推荐以下两种实用方案:

方案一:自定义注解+BeanDefinitionRegistryPostProcessor 实现批量注册

通过自定义注解标记测试类,配合Bean定义注册处理器,自动批量将指定服务替换为Mockito Mock对象,完全复刻原@MyMocksTest的使用体验。

1. 自定义标记注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyMocksTest {
    // 若需灵活指定Mock类,可添加value属性;固定Mock列表的话可省略
    Class<?>[] value() default {};
}

2. 实现批量Mock注册处理器

import org.mockito.Mockito;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class BatchMockitoBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    // 定义需要批量Mock的服务类列表
    private static final Class<?>[] TARGET_SERVICES = {
            ServiceA.class, ServiceB.class, ServiceC.class,
            // 追加其余20+个服务类
    };

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Arrays.stream(TARGET_SERVICES).forEach(serviceClass -> {
            String beanName = lowerFirstCase(serviceClass.getSimpleName());
            // 移除原有Bean定义(若存在),替换为Mock对象
            if (registry.containsBeanDefinition(beanName)) {
                registry.removeBeanDefinition(beanName);
            }
            // 构建Mockito Mock的Bean定义并注册
            BeanDefinition mockBeanDef = BeanDefinitionBuilder
                    .genericBeanDefinition(serviceClass, () -> Mockito.mock(serviceClass))
                    .setScope(BeanDefinition.SCOPE_SINGLETON)
                    .getBeanDefinition();
            registry.registerBeanDefinition(beanName, mockBeanDef);
        });
    }

    @Override
    public void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 无需额外处理
    }

    // 辅助方法:将类名首字母转为小写作为Bean名称
    private String lowerFirstCase(String className) {
        if (className == null || className.isEmpty()) {
            return className;
        }
        return className.substring(0, 1).toLowerCase() + className.substring(1);
    }
}

3. 测试类使用

只需在测试类上添加自定义注解即可自动注入所有Mock服务:

@SpringBootTest
@MyMocksTest
public class DemoServiceTest {
    @Autowired
    private ServiceA serviceA;
    @Autowired
    private ServiceB serviceB;

    @Test
    void testDefaultMockBehavior() {
        // 直接使用Mock对象,默认返回空值/Null,无需额外定义行为
        serviceA.doAction();
        serviceB.handleTask();
    }
}

方案二:测试配置类集中声明Mock Bean

如果对Bean处理器不太熟悉,可通过测试专用配置类集中定义所有Mock Bean,测试类只需引入该配置即可。

1. 创建Mock服务配置类

import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MockServicesConfig {

    @Bean
    @Primary // 确保Mock Bean优先注入,覆盖原服务Bean
    public ServiceA serviceA() {
        return Mockito.mock(ServiceA.class);
    }

    @Bean
    @Primary
    public ServiceB serviceB() {
        return Mockito.mock(ServiceB.class);
    }

    @Bean
    @Primary
    public ServiceC serviceC() {
        return Mockito.mock(ServiceC.class);
    }

    // 依次添加其余20+个服务的Mock Bean定义
}

2. 测试类引入配置

@SpringBootTest
@Import(MockServicesConfig.class)
public class OrderServiceTest {
    @Autowired
    private ServiceA serviceA;

    @Test
    void testBusinessFlow() {
        // 直接使用配置类中定义的Mock对象
        serviceA.execute();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:56:03