从Spring Boot 3.1.5迁移至3.2.0后单元测试失败求助
问题背景
我们近期将Spring Boot父依赖从3.1.5版本迁移至3.2.0版本:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath /> </parent>
迁移后单元测试失败,测试报告报错:
[ERROR] nl.gateway.WebControllerTest.indexRNB -- Time elapsed: 0.012 s <<< FAILURE! java.lang.AssertionError: Range for response status value 500 INTERNAL_SERVER_ERROR expected:<SUCCESSFUL> but was:<SERVER_ERROR> at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122) at org.springframework.test.web.reactive.server.StatusAssertions.lambda$assertSeriesAndReturn$5(StatusAssertions.java:244) at org.springframework.test.web.reactive.server.ExchangeResult.assertWithDiagnostics(ExchangeResult.java:222) at org.springframework.test.web.reactive.server.StatusAssertions.assertSeriesAndReturn(StatusAssertions.java:243) at org.springframework.test.web.reactive.server.StatusAssertions.is2xxSuccessful(StatusAssertions.java:187) at nl.gateway.WebControllerTest.indexRNB(WebControllerTest.java:100) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
IDE中捕获的详细错误栈:
java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.security.oauth2.core.oidc.user.OidcUser at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:267) ~[spring-beans-6.1.1.jar:6.1.1] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): *__checkpoint ⇢ org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$MutatorFilter [DefaultWebFilterChain] *__checkpoint ⇢ org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$OAuth2ClientMutator$$Lambda$1094/0x00000008011c7c38 [DefaultWebFilterChain] *__checkpoint ⇢ org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$SetupMutatorFilter [DefaultWebFilterChain] *__checkpoint ⇢ HTTP GET "/" [ExceptionHandlingWebHandler] Original Stack Trace:
相关代码片段:
单元测试代码:
@Test void indexRNB() { client .mutateWith(mockOidcLogin().idToken(id -> id .subject("Subject A") .claim("groups", List.of("ORG-RNB")))) .get().uri("/").exchange() .expectStatus().is2xxSuccessful() .expectBody().consumeWith(response -> assertThat(new String(response.getResponseBody())) .contains(">Logout Subject A")); }
控制器代码:
@GetMapping(value = "/") public String getIndex( @AuthenticationPrincipal(errorOnInvalidType = true) OidcUser user, @RequestParam MultiValueMap<String, String> params, Model model, @Value("${aggregatedvolumes.suppliers}") List<String> aggregatedvolumesSuppliers) { // Conditionally show links return "root"; }
尝试过降级多个依赖库但未解决问题,想问Spring Boot 3.1.5与3.2.0之间的哪些变更会引发这个问题?
问题分析及解决方法
核心变更原因
Spring Boot 3.2.0同步升级了Spring Security到6.1.x版本,该版本对OIDC测试模拟逻辑做了调整:mockOidcLogin()默认生成的认证主体不再是OidcUser实例,而是其父类AbstractOAuth2User(属于OAuth2User类型)。但你的控制器方法通过@AuthenticationPrincipal(errorOnInvalidType = true)强制绑定OidcUser接口,导致类型转换失败,抛出IllegalStateException,最终返回500服务器错误。
具体修复方案
在单元测试中,显式配置mockOidcLogin()生成OidcUser实例,通过user()方法指定构建逻辑:
@Test void indexRNB() { client .mutateWith(mockOidcLogin() .idToken(id -> id .subject("Subject A") .claim("groups", List.of("ORG-RNB"))) .user(oidcUser -> oidcUser .authorities(List.of(new SimpleGrantedAuthority("ROLE_USER"))))) // 根据业务需求添加权限 .get().uri("/").exchange() .expectStatus().is2xxSuccessful() .expectBody().consumeWith(response -> assertThat(new String(response.getResponseBody())) .contains(">Logout Subject A")); }
如果业务逻辑允许,也可以将控制器中的参数类型从OidcUser改为OAuth2User,这样无需修改测试代码,但需要评估是否会影响其他业务逻辑。
内容的提问来源于stack exchange,提问作者mocklek
相关产品推荐
相关产品推荐

