使用OpenAPI生成接口时MockMvc测试服务注入失败问题
问题原因分析
- @Validated 触发JDK动态代理:当Controller实现OpenAPI生成的接口且带有
@Validated注解(手动标注或接口继承),Spring的MethodValidationPostProcessor会为Controller创建JDK动态代理。JDK代理基于接口实现,仅代理接口声明的方法,且代理对象与原始Controller是独立实例。 - MockMvc测试的代理上下文冲突:MockMvc默认使用代理后的Controller处理请求,当参数校验抛出
MethodArgumentNotValidException时,异常处理器(如@RestControllerAdvice)中的CodeService可能未完成初始化,或代理机制导致异常处理器无法获取已初始化的实例。 - OpenAPI生成接口的注解传递:部分OpenAPI代码生成器会自动为生成的接口添加
@Validated注解以支持参数校验,即使你未手动给Controller标注,只要实现该接口就会触发代理逻辑,引发问题。
兼容OpenAPI生成接口的测试解决方案
方案1:强制使用CGLIB代理
修改测试环境的Spring配置,让@Validated标注的Controller使用CGLIB代理(基于类的代理,避免JDK代理的限制):
- 在
application-test.yml中添加:
spring: aop: proxy-target-class: true
- 或者在测试类上添加注解:
@EnableAspectJAutoProxy(proxyTargetClass = true)
CGLIB代理直接继承原始Controller类,能保证依赖注入的实例被正确传递,异常处理器中的CodeService可正常初始化。
方案2:显式初始化异常处理器依赖
在测试类中主动注入异常处理器和依赖服务,强制Spring提前完成初始化:
@SpringBootTest @AutoConfigureMockMvc public class MyControllerTest { @Autowired private MockMvc mockMvc; // 显式注入,确保Spring优先初始化这些Bean @Autowired private GlobalExceptionHandler exceptionHandler; @Autowired private CodeService codeService; // 测试方法示例 @Test void testInvalidRequest() throws Exception { mockMvc.perform(post("/api/xxx") .contentType(MediaType.APPLICATION_JSON) .content("{\"invalidField\": \"xxx\"}")) .andExpect(status().isBadRequest()); } }
方案3:手动构建MockMvc(绕开代理)
不依赖@AutoConfigureMockMvc,直接用原始Controller实例构建MockMvc,避免代理机制的影响:
@SpringBootTest public class MyControllerTest { @Autowired private MyController targetController; @Autowired private GlobalExceptionHandler exceptionHandler; private MockMvc mockMvc; @BeforeEach void setUp() { // 直接使用原始Controller实例,手动注册异常处理器 mockMvc = MockMvcBuilders.standaloneSetup(targetController) .setControllerAdvice(exceptionHandler) .build(); } // 测试方法... }
方案4:调整OpenAPI生成配置
如果使用OpenAPI Generator,修改配置避免生成的接口携带@Validated注解:
- Maven插件示例(在
pom.xml的openapi-generator-maven-plugin中添加):
<configuration> <generatorName>spring</generatorName> <configOptions> <validatedAnnotation>false</validatedAnnotation> </configOptions> </configuration>
之后你可以手动在Controller类上添加@Validated注解(此时若Controller无其他接口依赖,Spring会自动使用CGLIB代理),或根据需求调整参数校验逻辑。
内容的提问来源于stack exchange,提问作者Syrious
相关产品推荐
相关产品推荐

