移除@Lazy注解后,如何正确测试Spring配置类中的Bean?
解决方法
你的问题核心是错误地把纯单元测试和Spring容器启动绑定在了一起——这个测试本来只需要验证credentialsProvider方法的逻辑,完全不需要启动Spring容器。直接去掉@SpringBootTest注解,用纯Mockito测试就能解决问题:
修改后的测试类代码:
@ExtendWith(MockitoExtension.class) final class AwsConfigurationTests { @Mock private AwsCredentialsProperties credentialsProperties; @InjectMocks private AwsConfiguration awsConfiguration; @Test void profilePathIsNull() { when(credentialsProperties.getProfilePath()).thenReturn(null); assertThrows(IllegalArgumentException.class, () -> awsConfiguration.credentialsProvider(credentialsProperties), "No profile path specified."); } }
为什么这样能解决?
原来的@SpringBootTest会强制启动Spring容器,并尝试实例化你指定的AwsConfiguration里所有非懒加载的Bean。移除@Lazy后,Spring启动时就会调用credentialsProvider方法,但此时容器里没有AwsCredentialsProperties的Bean,所以报错。
而去掉@SpringBootTest后,测试完全脱离Spring容器:@Mock和@InjectMocks都是Mockito的功能,只是帮你创建Mock对象并注入到AwsConfiguration实例中,直接调用方法验证逻辑即可,根本不会触发Spring的Bean实例化流程,自然就没有冲突了。
如果你的测试场景确实需要启动Spring容器(比如要验证Bean之间的依赖关系),可以用以下方式处理:
- 用
@MockBean替代@Mock,把Mock的AwsCredentialsProperties注册到Spring容器中 - 但此时Spring启动时会自动调用
credentialsProvider方法创建Bean,会直接触发异常导致测试失败,所以需要在测试前先设置好Mock的返回值,可以用@BeforeEach:
@SpringBootTest( classes = {AwsConfiguration.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE ) final class AwsConfigurationTests { @MockBean private AwsCredentialsProperties credentialsProperties; @Autowired private AwsConfiguration awsConfiguration; @BeforeEach void setUp() { // 先设置默认返回值,避免Spring启动时触发异常 when(credentialsProperties.getProfilePath()).thenReturn("dummy-path"); } @Test void profilePathIsNull() { // 测试时覆盖返回值 when(credentialsProperties.getProfilePath()).thenReturn(null); assertThrows(IllegalArgumentException.class, () -> awsConfiguration.credentialsProvider(credentialsProperties), "No profile path specified."); } }
不过这种方式略显繁琐,对于纯方法逻辑验证,还是第一种纯Mockito测试更简洁高效。
内容的提问来源于stack exchange,提问作者Oliver
相关产品推荐
相关产品推荐

