Spring Boot下Mockito测试WebClient初始化失败问题求助
问题描述
我正在开发基于Java Spring Boot 2.x和Java 1.8的项目,依赖JUnit 4.13.2与Mockito 3.12.4。编写StarshipService测试时遇到以下问题:
- 最初
@Before注解的setup方法无法执行(调试无法命中断点),导致webClientBuilder为null,初始化StarshipService时抛出InjectMocksException,报错信息为:无法调用WebClient.Builder.build(),因为baseUrl返回值为null。 - 后续调整后能进入setup方法,但
webClientBuilder仍为null,调用when()方法时程序崩溃。
项目中已通过AppConfig配置WebClient.Builder Bean,StarshipService通过构造注入该Builder并初始化WebClient。
服务类代码
@Service public class StarshipService { private final WebClient webClient; @Autowired public StarshipService(WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.baseUrl("https://www.swapi.tech/api").build(); } public StarshipResponse getStarships(int page, int size, String nameOrId){ try { // 如果nameOrId是数字,按ID查询 if (nameOrId != null && nameOrId.matches("\\d+")) { return getStarshipById(nameOrId); } UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://www.swapi.tech/api/starships"); if (page != 0){ builder.queryParam("page", page); } builder.queryParam("limit", size); if (nameOrId != null && !nameOrId.isEmpty()) { builder.queryParam("name", nameOrId); } String url = builder.toUriString(); Mono<ResponseEntity<String>> responseMono = this.webClient.get() .uri(url) .retrieve() .toEntity(String.class); ResponseEntity<String> responseEntity = responseMono.block(); if (responseEntity != null && responseEntity.getStatusCode().is2xxSuccessful()) { String responseBody = responseEntity.getBody(); if (responseBody != null && responseBody.contains("results")) { return StarWarsParseService.parseStandardStarshipResponse(responseBody); } else if (responseBody != null && responseBody.contains("result")) { return StarWarsParseService.parseSearchStarshipResponse(responseBody); } } return new StarshipResponse(); } catch (HttpClientErrorException e){ System.err.println("调用Star Wars API出错: " + e.getMessage()); e.printStackTrace(); return new StarshipResponse(); } catch (JsonProcessingException e) { throw new RuntimeException(e); } } public StarshipResponse getStarshipById(String id) throws JsonProcessingException { try { String url = "https://www.swapi.tech/api/starships/" + id; Mono<ResponseEntity<String>> responseMono = this.webClient.get() .uri(url) .retrieve() .toEntity(String.class); try{ ResponseEntity<String> responseEntity = responseMono.block(); if (responseEntity != null && responseEntity.getStatusCode().is2xxSuccessful()) { return StarWarsParseService.parseIdStarshipResponse(responseEntity.getBody()); } else { System.err.println("意外响应或状态码: " + responseEntity); return new StarshipResponse(); } }catch (WebClientResponseException.NotFound ex){ System.err.println("SWAPI中未找到ID为" + id + "的飞船"); StarshipResponse starshipResponse = new StarshipResponse(); starshipResponse.setResults(new ArrayList<>()); starshipResponse.setTotal_records(0); starshipResponse.setTotal_pages(1); return starshipResponse; } } catch (HttpClientErrorException e) { System.err.println("调用Star Wars API出错: " + e.getMessage()); e.printStackTrace(); return new StarshipResponse(); } catch (Exception e) { System.err.println("意外错误: " + e.getMessage()); e.printStackTrace(); return new StarshipResponse(); } } }
测试类代码
@RunWith(MockitoJUnitRunner.class) @SpringBootTest public class StarshipServiceTest { @Mock private WebClient.Builder webClientBuilder; @Mock private WebClient webClient; @Mock private WebClient.RequestHeadersUriSpec requestHeadersUriSpec; @Mock private WebClient.RequestHeadersSpec requestHeadersSpec; @Mock private WebClient.ResponseSpec responseSpec; @InjectMocks private StarshipService starshipService; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(webClientBuilder.baseUrl(anyString())).thenReturn(webClientBuilder); when(webClientBuilder.build()).thenReturn(webClient); } @Test public void testGetStarships() throws JsonProcessingException { // 模拟WebClient行为 when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(anyString())).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); when(responseSpec.toEntity(String.class)).thenReturn(Mono.just(new ResponseEntity<>("{\"results\": []}", HttpStatus.OK))); // 调用测试方法 StarshipResponse response = starshipService.getStarships(1, 10, null); // 断言响应 assertNotNull(response); assertEquals(0, response.getResults().size()); } @Test public void testGetStarshipById() throws JsonProcessingException { // 模拟WebClient行为 when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(anyString())).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); when(responseSpec.toEntity(String.class)).thenReturn(Mono.just(new ResponseEntity<>("{\"result\": {\"properties\": {\"name\": \"Millennium Falcon\"}}}", HttpStatus.OK))); // 调用测试方法 StarshipResponse response = starshipService.getStarshipById("10"); // 断言响应 assertNotNull(response); assertEquals("Millennium Falcon", response.getResults().get(0).getName()); } @Test public void testGetStarshipByIdNotFound() throws JsonProcessingException { // 模拟WebClient返回404 Not Found的行为 when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(anyString())).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); when(responseSpec.toEntity(String.class)).thenReturn(Mono.error(new WebClientResponseException(404, "Not Found", null, null, null))); // 调用测试方法 StarshipResponse response = starshipService.getStarshipById("0"); // 断言响应 assertNotNull(response); assertEquals(0, response.getTotal_records()); } }
配置类代码
@Configuration public class AppConfig { @Bean public WebClient.Builder webClientBuilder() { return WebClient.builder(); } }
内容的提问来源于stack exchange,提问作者Juan Federico Di Leo
相关产品推荐
相关产品推荐

