集成测试报错:如何配置TestRestTemplate使用密钥库及适配MockMvc?
解决OAuth2资源服务器集成测试的TestRestTemplate和MockMvc问题
针对你遇到的这个问题,我分两部分来给出具体解决方案,分别对应TestRestTemplate的SSL配置问题和MockMvc的测试适配:
一、配置TestRestTemplate使用指定的信任库
你的TestRestTemplate测试失败核心原因是:它默认不会继承应用启动时通过VM参数指定的SSL信任库配置,导致调用用户信息端点时触发证书验证失败。你可以通过两种方式解决:
方法1:在测试类中自定义带SSL配置的TestRestTemplate
直接在测试代码里为TestRestTemplate加载指定的信任库,这样测试请求就会和应用使用相同的证书信任策略:
import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.test.web.client.TestRestTemplate; import javax.net.ssl.SSLContext; import org.apache.http.ssl.SSLContextBuilder; import java.io.File; @SpringBootTest public class YourIntegrationTest { @Autowired private Environment environment; @Bean public TestRestTemplate trustedTestRestTemplate() throws Exception { // 从环境变量中读取应用启动时指定的信任库配置 String trustStorePath = environment.getProperty("javax.net.ssl.trustStore"); String trustStorePassword = environment.getProperty("javax.net.ssl.trustStorePassword"); // 构建加载了目标信任库的SSL上下文 SSLContext sslContext = SSLContextBuilder.create() .loadTrustMaterial(new File(trustStorePath), trustStorePassword.toCharArray()) .build(); // 创建带有自定义SSL配置的HttpClient HttpClient httpClient = HttpClientBuilder.create() .setSSLContext(sslContext) .build(); // 配置请求工厂并初始化TestRestTemplate HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return new TestRestTemplate(factory); } // 在测试方法中注入这个自定义的TestRestTemplate @Autowired private TestRestTemplate trustedTestRestTemplate; @Test public void testSecuredApiCall() { ResponseEntity<String> response = trustedTestRestTemplate.getForEntity("/your-api-endpoint", String.class); // 这里添加你的断言逻辑 } }
方法2:为测试运行传递相同的VM参数
如果你不想写代码配置,也可以在IDE的测试运行配置中,添加和应用启动完全一致的VM参数:
-Djavax.net.ssl.trustStore=<本地证书存储路径> -Djavax.net.ssl.trustStorePassword=<密码>
这样TestRestTemplate会自动继承这个信任库配置,无需额外代码修改。
二、MockMvc的测试适配
MockMvc是在Servlet容器内部模拟请求,不会涉及真实的SSL连接,所以它的失败大概率和资源服务器的认证逻辑有关,而非SSL问题。结合你当前permitAll的安全配置,可以通过以下方式调整:
方式1:Mock资源服务器的Token服务
即使你配置了permitAll,资源服务器的过滤器仍可能尝试验证请求中的token,导致测试失败。你可以mock掉RemoteTokenServices来绕过真实的授权服务器调用:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc public class YourMockMvcTest { @Autowired private MockMvc mockMvc; // Mock掉Token服务,避免真实调用授权服务器 @MockBean private RemoteTokenServices remoteTokenServices; @Test public void testPublicEndpoint() throws Exception { mockMvc.perform(get("/public-endpoint")) .andExpect(status().isOk()); } }
方式2:临时禁用资源服务器配置
如果你的测试完全不需要资源服务器的逻辑,可以直接在测试类中排除资源服务器的自动配置:
@SpringBootTest(exclude = {ResourceServerAutoConfiguration.class}) @AutoConfigureMockMvc public class YourMockMvcTest { // 测试代码... }
方式3:模拟认证用户(后续场景适配)
如果后续你调整了安全配置,不再是全量permitAll,需要测试认证后的接口,可以使用@WithMockUser注解快速模拟登录用户:
@Test @WithMockUser(username = "test-user", roles = "USER") public void testSecuredEndpoint() throws Exception { mockMvc.perform(get("/secured-endpoint")) .andExpect(status().isOk()); }
内容的提问来源于stack exchange,提问作者Space Cadet
相关产品推荐
相关产品推荐

