运行EmployeeControllerTest遇依赖错误,求不修改控制器的解决方案
问题:Spring WebFlux测试中控制器依赖注入失败
错误信息:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '....controllers.EmployeeController': Unsatisfied dependency expressed through field 'testService1': No qualifying bean of type '...services.TestService1' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
已尝试的解决方法
- 使用反射设置私有字段
- 在测试类中使用构造函数注入
- 创建Test Configuration类添加所需Bean
- 手动配置依赖
相关代码
测试类代码
@ContextConfiguration(classes = {TestConfiguration.class}) @WebFluxTest(controllers = EmployeeController.class) @Profile("local") public class EmployeeControllerTest { @MockBean private TestService1 testService1; @MockBean private TestService2 testService2; private WebTestClient webTestClient; /* 如果给这个字段加@Autowired,会报UnsatisfiedDependencyException: Error creating bean due to an unsatisfied dependency expressed through the field 'webTestClient'.*/ @InjectMocks private EmployeeController employeeController; private JwtAuthenticationToken jwtAuthenticationToken; int pageIndex=0; int pageSize=10; @BeforeEach void setup(){ MockitoAnnotations.openMocks(this); jwtAuthenticationToken = mock(JwtAuthenticationToken.class); when(jwtAuthenticationToken.getName()).thenReturn("testUser"); /*如果不写下面这段代码,会报错:Cannot invoke "org.springframework.test.web.reactive.server.WebTestClient.post()" because "this.webTestClient" is null.*/ webTestClient = WebTestClient.bindToController(employeeController).webFilter(new SecurityContextServerWebExchangeWebFilter()).build(); } @Test void testEmployee(){ Page<EmployeeDto> mockPage = new PageImpl<>(Collections.emptyList()); when(testService1.list(eq(jwtAuthenticationToken), eq(pageIndex), eq(pageSize))).thenReturn(Mono.just(mockPage)); webTestClient.post() .uri("/test/employee/{index}/{size}",pageIndex,pageSize).exchange().expectStatus().isOk().expectBodyList(EmployeeDto.class).hasSize(0); }}
控制器代码(禁止修改)
@RestController @RequestMapping("/test") public class EmployeeController { @Autowired //不推荐字段注入 private TestService1 testService1; @Autowired //不推荐字段注入 private TestService2 testService2; @PostMapping("/employee/{index}/{size}") public Mono<Page<EmployeeDto>> users(@NonNull JwtAuthenticationToken principal, @PathVariable int index, @PathVariable int size) { return testService1.list(principal, index, size); } }
问题原因及解决方案
原因分析
测试类同时混用了Spring Boot的@WebFluxTest和Mockito的@InjectMocks,引发冲突:
@WebFluxTest会自动创建WebFlux上下文并初始化EmployeeController,但此时控制器依赖的服务Bean和@InjectMocks的手动注入逻辑冲突,导致Spring找不到合格的Bean。@InjectMocks是Mockito手动注入Mock的注解,和Spring上下文的Bean管理机制不兼容,控制器被Spring和Mockito双重实例化,最终触发依赖注入失败。
修正方案
移除@InjectMocks和手动实例化控制器、构建WebTestClient的逻辑,完全依赖@WebFluxTest的自动配置:
修改后的测试类代码:
@WebFluxTest(controllers = EmployeeController.class) @Profile("local") // 若TestConfiguration非必需可移除,避免配置冲突 // @ContextConfiguration(classes = {TestConfiguration.class}) public class EmployeeControllerTest { @MockBean private TestService1 testService1; @MockBean private TestService2 testService2; @Autowired private WebTestClient webTestClient; private JwtAuthenticationToken jwtAuthenticationToken; int pageIndex = 0; int pageSize = 10; @BeforeEach void setup() { jwtAuthenticationToken = mock(JwtAuthenticationToken.class); when(jwtAuthenticationToken.getName()).thenReturn("testUser"); // 配置Reactive SecurityContext,让请求携带认证信息 SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); securityContext.setAuthentication(jwtAuthenticationToken); webTestClient = webTestClient.mutate() .webFilter((exchange, chain) -> { exchange.getAttributes().put(SecurityContextServerWebExchangeWebFilter.SECURITY_CONTEXT_ATTR, Mono.just(securityContext)); return chain.filter(exchange); }) .build(); } @Test void testEmployee() { Page<EmployeeDto> mockPage = new PageImpl<>(Collections.emptyList()); when(testService1.list(eq(jwtAuthenticationToken), eq(pageIndex), eq(pageSize))).thenReturn(Mono.just(mockPage)); webTestClient.post() .uri("/test/employee/{index}/{size}", pageIndex, pageSize) .exchange() .expectStatus().isOk() .expectBodyList(EmployeeDto.class).hasSize(0); } }
关键修改点
- 删除
@InjectMocks和手动创建的控制器实例,让@WebFluxTest自动管理控制器Bean。 - 直接
@Autowired获取WebTestClient,Spring会基于上下文自动构建,无需手动绑定控制器。 - 通过
WebTestClient.mutate()添加过滤器设置SecurityContext,替代手动构建WebTestClient的逻辑,保证请求携带认证信息。 - 非必需情况下移除
@ContextConfiguration,避免额外配置引发冲突。
修改后,Spring上下文会正确识别@MockBean声明的服务Bean并注入到控制器中,解决依赖找不到的问题,同时WebTestClient也能正常注入。
内容的提问来源于stack exchange,提问作者Nootan Heroorkar
相关产品推荐
相关产品推荐

