使用@InjectMocks模拟ProcessorFactory组件在测试中失效问题排查
问题原因分析
- Mockito @InjectMocks的实例创建逻辑:
@InjectMocks默认通过无参构造函数(若存在)反射生成实例,不会主动调用你定义的带List<Processor>参数的构造函数,这直接导致静态processorCache未被初始化——构造函数根本没执行。 - 静态缓存与依赖注入的冲突:运行时Spring会管理
ProcessorFactory的生命周期,主动调用带参构造函数完成注入;但测试中使用Mockito时,它不参与Spring上下文管理,只是单纯实例化对象,自然不会触发Spring的注入逻辑。
解决方案
方案1:改用Spring Boot测试框架,让Spring管理测试上下文
放弃纯Mockito测试,使用@SpringBootTest或@WebMvcTest(针对Web层),配合@MockBean替换需要模拟的Processor子类:
@SpringBootTest class ProcessorFactoryTest { @Autowired private ProcessorFactory processorFactory; // 模拟特定Processor子类 @MockBean private ProcessorType1 processorType1; @Test void testGetProcessor() { // 给定模拟逻辑 when(processorType1.getType()).thenReturn(Type.TYPE1); // 执行测试 Processor processor = processorFactory.getProcessor(Type.TYPE1); assertNotNull(processor); } }
这样Spring会正常初始化ProcessorFactory,调用带参构造函数填充List<Processor>,同时用@MockBean替换真实的ProcessorType1实例。
方案2:调整ProcessorFactory的初始化逻辑,兼容Mockito测试
给ProcessorFactory添加一个初始化方法,手动触发缓存加载,测试时主动调用:
@Component public class ProcessorFactory { private static final Map<Type, Processor> processorCache = new HashMap<>(); // 构造函数注入 public ProcessorFactory(List<Processor> processors) { initCache(processors); } // 暴露初始化方法给测试用 public static void initCache(List<Processor> processors) { processorCache.clear(); processors.forEach(p -> processorCache.put(p.getType(), p)); } // 静态获取方法 public static Processor getProcessor(Type type) { return processorCache.get(type); } }
测试类中手动初始化缓存:
class ProcessorFactoryTest { @Mock private ProcessorType1 processorType1; private ProcessorFactory processorFactory; @BeforeEach void setUp() { // 手动构造实例并初始化缓存 processorFactory = new ProcessorFactory(List.of(processorType1)); // 或者直接调用静态初始化方法 ProcessorFactory.initCache(List.of(processorType1)); when(processorType1.getType()).thenReturn(Type.TYPE1); } @Test void testGetProcessor() { Processor processor = ProcessorFactory.getProcessor(Type.TYPE1); assertEquals(processorType1, processor); } }
这种方式不需要Spring上下文,纯Mockito即可完成测试,同时兼容原有运行时逻辑。
方案3:重构ProcessorFactory,去掉静态依赖(推荐)
静态缓存会导致测试难维护,建议把processorCache改为实例变量,让ProcessorFactory成为普通Spring组件,通过依赖注入使用:
@Component public class ProcessorFactory { private final Map<Type, Processor> processorCache; public ProcessorFactory(List<Processor> processors) { this.processorCache = processors.stream() .collect(Collectors.toMap(Processor::getType, p -> p)); } // 去掉static,改成实例方法 public Processor getProcessor(Type type) { return processorCache.get(type); } }
然后MyService中通过@Autowired注入ProcessorFactory:
@Service public class MyService { private final ProcessorFactory processorFactory; @Autowired public MyService(ProcessorFactory processorFactory) { this.processorFactory = processorFactory; } public void doSomething(Type type) { Processor processor = processorFactory.getProcessor(type); // 执行逻辑 } }
测试时用@InjectMocks或Spring注入都能正常工作,彻底解决静态与依赖注入的冲突。
内容的提问来源于stack exchange,提问作者Timothy Clotworthy
相关产品推荐
相关产品推荐

