最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - MockMvc Test doesnt work when internal API is called - Stack Overflow

programmeradmin2浏览0评论

I am developing a Spring Boot application/library where i have a Service that sends a request to a an API. When in integration Test the Entry Point into the Service is an /integration Endpoint. The following Code is the mvp to reproduce the error

Main Service:

@Service
@RequiredArgsConstructor
public class CalculationService {

  private final RestClient restClient;

  public CalculationResponse calculate(CalculationRequest request){
    return restClient.post().uri("/service/calculate")
        .body(request)
        .retrieve()
        .toEntity(CalculationResponse.class).getBody();

  }
}

Main Controller

@RestController
@RequestMapping("/service")
public class MockApi {


  @PostMapping("/calculate")
  public CalculationResponse calculate(@RequestBody CalculationRequest calculationRequest) {
    CalculationResponse calculationResponse = new CalculationResponse();
    calculationResponse.setSummary(calculationRequest.getName()+ "----" + calculationRequest.getValue());
    return calculationResponse;
  }
}

The Entry Point for my Integration Test

@RestController
@RequestMapping
@RequiredArgsConstructor
public class TestController {

  private final CalculationService calculationService;

  @PostMapping("/integration")
  public CalculationResponse integration(@RequestBody CalculationRequest request) {
    return calculationService.calculate(request);
  }

}

RestClient Configuration

@Configuration
public class CalculationConfiguration {


  @Bean
  public RestClient restClient() {
    return RestClient.builder()
        .baseUrl("http://localhost:8080")
        .build();
  }

}

Integration Test

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
public class IntegrationTest {

  @Autowired
  private MockMvc mockMvc;

  @Autowired
  private ObjectMapper objectMapper;

  @Test
  public void thatSummaryIsReturned() throws Exception {

    CalculationRequest request = new CalculationRequest("Test", "Value");
    mockMvc.perform(MockMvcRequestBuilders.post("/integration")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(request)))
        .andExpect(status().isOk())
        .andReturn();
  }

}

When running the test i receive following error:

Request processing failed: .springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/service/calculate": null jakarta.servlet.ServletException: Request processing failed: .springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/service/calculate": null at .springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1022) at .springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) at .springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at .springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)

When i change the endpoint in my integration test directly to /service/calculate it works. I tried to debug but when having /integration as path in the test i dont even react the other endpoint. Has anyone an idea why this is the case ?

Edit: When the Application runs in the Background it works. So it seems that there is something missing in my TestContext ...

I am developing a Spring Boot application/library where i have a Service that sends a request to a an API. When in integration Test the Entry Point into the Service is an /integration Endpoint. The following Code is the mvp to reproduce the error

Main Service:

@Service
@RequiredArgsConstructor
public class CalculationService {

  private final RestClient restClient;

  public CalculationResponse calculate(CalculationRequest request){
    return restClient.post().uri("/service/calculate")
        .body(request)
        .retrieve()
        .toEntity(CalculationResponse.class).getBody();

  }
}

Main Controller

@RestController
@RequestMapping("/service")
public class MockApi {


  @PostMapping("/calculate")
  public CalculationResponse calculate(@RequestBody CalculationRequest calculationRequest) {
    CalculationResponse calculationResponse = new CalculationResponse();
    calculationResponse.setSummary(calculationRequest.getName()+ "----" + calculationRequest.getValue());
    return calculationResponse;
  }
}

The Entry Point for my Integration Test

@RestController
@RequestMapping
@RequiredArgsConstructor
public class TestController {

  private final CalculationService calculationService;

  @PostMapping("/integration")
  public CalculationResponse integration(@RequestBody CalculationRequest request) {
    return calculationService.calculate(request);
  }

}

RestClient Configuration

@Configuration
public class CalculationConfiguration {


  @Bean
  public RestClient restClient() {
    return RestClient.builder()
        .baseUrl("http://localhost:8080")
        .build();
  }

}

Integration Test

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
public class IntegrationTest {

  @Autowired
  private MockMvc mockMvc;

  @Autowired
  private ObjectMapper objectMapper;

  @Test
  public void thatSummaryIsReturned() throws Exception {

    CalculationRequest request = new CalculationRequest("Test", "Value");
    mockMvc.perform(MockMvcRequestBuilders.post("/integration")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(request)))
        .andExpect(status().isOk())
        .andReturn();
  }

}

When running the test i receive following error:

Request processing failed: .springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/service/calculate": null jakarta.servlet.ServletException: Request processing failed: .springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/service/calculate": null at .springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1022) at .springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) at .springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at .springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)

When i change the endpoint in my integration test directly to /service/calculate it works. I tried to debug but when having /integration as path in the test i dont even react the other endpoint. Has anyone an idea why this is the case ?

Edit: When the Application runs in the Background it works. So it seems that there is something missing in my TestContext ...

Share Improve this question edited Mar 14 at 20:59 Artem Bilan 122k11 gold badges102 silver badges129 bronze badges asked Mar 14 at 20:33 BonBonnBonBonn 294 bronze badges 4
  • pls add your integration test code – Geii Lvov Commented Mar 14 at 20:39
  • Added the test code. The whole sourcecode is here: github/bonbonn1912/mock-mvc-error this is a repository to reproduce the error. – BonBonn Commented Mar 14 at 20:39
  • And this only happens when the restclient performs a request to an internal controller. So when going to an external endpoint it works. The TestController Bean is also in the ApplicationContext and works when the mockmvc directly calls it ... – BonBonn Commented Mar 14 at 20:44
  • If this is a full on integration test, provide a way to pass the port when creating your RestClient and pass it through your test configuration. – Sotirios Delimanolis Commented Mar 14 at 22:11
Add a comment  | 

1 Answer 1

Reset to default 2

The issue occurs because you are using @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT), which starts your application on a random port. However, your RestClient is explicitly configured to use http://localhost:8080, leading to a port mismatch. Since the application is not actually running on port 8080 during the test, requests fail with an I/O error when trying to reach http://localhost:8080/service/calculate.

One solution is to start the test on a defined port:

@SpringBootTest(
     webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, 
     properties = "server.port=8080"
)
发布评论

评论列表(0)

  1. 暂无评论