You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行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);  
    }  
}

关键修改点

  1. 删除@InjectMocks和手动创建的控制器实例,让@WebFluxTest自动管理控制器Bean。
  2. 直接@Autowired获取WebTestClient,Spring会基于上下文自动构建,无需手动绑定控制器。
  3. 通过WebTestClient.mutate()添加过滤器设置SecurityContext,替代手动构建WebTestClient的逻辑,保证请求携带认证信息。
  4. 非必需情况下移除@ContextConfiguration,避免额外配置引发冲突。

修改后,Spring上下文会正确识别@MockBean声明的服务Bean并注入到控制器中,解决依赖找不到的问题,同时WebTestClient也能正常注入。

内容的提问来源于stack exchange,提问作者Nootan Heroorkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:22:03