Spring Boot @WebMvcTest测试控制器遇URI非绝对错误,如何解决?
我在Spring Boot 3.2.2应用里有个控制器,能正常解析Auth0/Okta提供的OAuth2 Token并根据内容返回响应。但编写@WebMvcTest测试用例时遇到错误。
测试代码如下:
@WebMvcTest(MembersController::class) class MembersControllerTest(@Autowired val mockMvc: MockMvc) { @Test fun `should return 403 when name in token is unknown`() { val oauth2User = DefaultOAuth2User( setOf(), // Authorities mapOf("sub" to "123", "name" to "someUnknownName", "email" to "john@example.com"), "sub" ) mockMvc.post("/api/v1/members") { with(oauth2Login().oauth2User(oauth2User)) } .andExpect { status { isUnauthorized() } } } }
运行测试时抛出错误:
ERROR org.springframework.boot.SpringApplication -- Application run failed java.lang.IllegalArgumentException: URI is not absolute
调试发现问题URL为/.well-known/openid-configuration,堆栈信息指向Okta Starter组件:
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:781) at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:422) at com.okta.spring.boot.oauth.env.OktaOAuth2PropertiesMappingEnvironmentPostProcessor.postProcessEnvironment(OktaOAuth2PropertiesMappingEnvironmentPostProcessor.java:122) at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109) at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
想了解是否有办法绕过该问题继续使用@WebMvcTest,还是必须改用@SpringBootTest并携带真实Token发送请求测试。
以下几种方法可以让你继续使用@WebMvcTest完成测试,无需切换到@SpringBootTest:
方法1:排除Okta自动配置类
在@WebMvcTest注解中添加excludeAutoConfiguration,排除Okta的OAuth2自动配置类,避免测试上下文加载时触发Okta的配置逻辑:@WebMvcTest( MembersController::class, excludeAutoConfiguration = [OktaOAuth2AutoConfiguration::class] ) class MembersControllerTest(@Autowired val mockMvc: MockMvc) { // 原测试代码保持不变 }方法2:设置测试环境的Okta Issuer属性
通过@TestPropertySource给测试环境设置一个虚假但合法的绝对URL作为Okta issuer,让Okta的配置处理器能正常初始化,不会抛出URI错误:@WebMvcTest(MembersController::class) @TestPropertySource(properties = ["okta.oauth2.issuer=https://fake-issuer.okta.com/oauth2/default"]) class MembersControllerTest(@Autowired val mockMvc: MockMvc) { // 原测试代码保持不变 }方法3:模拟OAuth2相关依赖Bean
如果控制器依赖OAuth2相关的服务类,可以通过@MockBean模拟这些组件,替换掉自动配置的Okta实现,阻止真实的配置加载流程:@WebMvcTest(MembersController::class) class MembersControllerTest(@Autowired val mockMvc: MockMvc) { @MockBean lateinit var oAuth2UserService: OAuth2UserService<OAuth2UserRequest, OAuth2User> // 原测试代码保持不变 }
优先推荐方法1或2,操作简单直接,能快速解决问题。
内容的提问来源于stack exchange,提问作者Vincent F

