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

如何在Spring Boot单元测试中正确读取测试属性文件

问题解决步骤

1. 修正测试配置文件的属性值

首先,application-test.properties中的属性值不需要加引号,Spring会将引号视为值的一部分,导致后续判断逻辑不符合预期。修改后的配置如下:

spring.security.oauth2.client.registration.cognito.clientId=testClientId
spring.security.oauth2.client.registration.cognito.clientSecret=testClientSecret

2. 让Spring容器管理SecurityConfiguration实例

你手动new SecurityConfiguration()的方式会绕过Spring的依赖注入机制,@Value注解完全不生效,导致成员变量为null触发空指针异常。需要让测试上下文加载该配置类,并通过Spring容器注入实例。

3. 重构单元测试类

使用@ContextConfiguration或@SpringBootTest加载配置类,结合@Autowired注入SecurityConfiguration,同时正确模拟HttpSecurity的链式调用(因为HttpSecurity的方法是链式调用,需要mock每个步骤的返回值):

@ContextConfiguration(classes = SecurityConfiguration.class)
@TestPropertySource("classpath:application-test.properties")
@ExtendWith(SpringExtension.class)
public class SecurityConfigurationTest {

    @Autowired
    private SecurityConfiguration securityConfiguration;

    @Test
    void filterChain_WithValidCognitoConfigs_ShouldApplySecurityRules() throws Exception {
        // Mock HttpSecurity及其链式调用的各个环节
        HttpSecurity httpMock = mock(HttpSecurity.class);
        CsrfConfigurer<HttpSecurity> csrfConfigurerMock = mock(CsrfConfigurer.class);
        AuthorizeRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authzMock = 
            mock(AuthorizeRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry.class);
        OAuth2LoginConfigurer<HttpSecurity> oauth2LoginMock = mock(OAuth2LoginConfigurer.class);
        LogoutConfigurer<HttpSecurity> logoutMock = mock(LogoutConfigurer.class);

        // 模拟链式调用的返回值
        when(httpMock.csrf()).thenReturn(csrfConfigurerMock);
        when(csrfConfigurerMock.and()).thenReturn(httpMock);
        when(httpMock.authorizeRequests()).thenReturn(authzMock);
        when(authzMock.anyRequest().authenticated()).thenReturn(authzMock);
        when(authzMock.and()).thenReturn(httpMock);
        when(httpMock.oauth2Login()).thenReturn(oauth2LoginMock);
        when(oauth2LoginMock.and()).thenReturn(httpMock);
        when(httpMock.logout()).thenReturn(logoutMock);
        when(logoutMock.logoutSuccessUrl("/")).thenReturn(logoutMock);
        when(httpMock.build()).thenReturn(mock(SecurityFilterChain.class));

        // 执行测试方法
        SecurityFilterChain filterChain = securityConfiguration.filterChain(httpMock);

        // 断言与验证
        assertNotNull(filterChain);
        verify(httpMock).csrf();
        verify(authzMock).anyRequest().authenticated();
        verify(logoutMock).logoutSuccessUrl("/");
    }

    @Test
    void filterChain_WithoutCognitoConfigs_ShouldPermitAll() throws Exception {
        // 可以通过覆盖属性值模拟空配置场景
        try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext()) {
            EnvironmentTestUtils.addEnvironment(context,
                "spring.security.oauth2.client.registration.cognito.clientId=",
                "spring.security.oauth2.client.registration.cognito.clientSecret=");
            context.register(SecurityConfiguration.class);
            context.refresh();

            SecurityConfiguration config = context.getBean(SecurityConfiguration.class);
            HttpSecurity httpMock = mock(HttpSecurity.class);
            when(httpMock.antMatcher("/**")).thenReturn(httpMock);
            when(httpMock.build()).thenReturn(mock(SecurityFilterChain.class));

            SecurityFilterChain filterChain = config.filterChain(httpMock);

            assertNotNull(filterChain);
            verify(httpMock).antMatcher("/**");
        }
    }
}

关键原因说明

  • @Value注解只有在Spring容器管理的Bean实例上才会生效,手动new的对象无法触发属性注入。
  • @WebMvcTest(SendMessageController.class)是针对Web层的切片测试,只会加载与指定Controller相关的Bean,不会加载SecurityConfiguration这类全局配置类。
  • 测试配置文件中的引号会导致属性值包含多余的引号,可能影响isBlank()的判断结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:45:21