GitHub Actions中Spring Boot Rest服务调用失败:JUnit测试连接拒绝
RestTemplate JUnit测试在GitHub Actions中连接被拒绝的问题分析与解决
错误信息
java.lang.RuntimeException: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:0/print/invoice": Connection refused at se.winassist.PrintingAppTest.testGetPrintableDocumentEN(PrintingAppTest.java:75) Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:0/print/invoice": Connection refused at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:915) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:895) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:672) at se.winassist.PrintingAppTest.testGetPrintableDocumentEN(PrintingAppTest.java:73)
测试代码
@ExtendWith({SpringExtension.class}) @SpringBootTest(classes = {PrintingApp.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class PrintingAppTest { @LocalServerPort int randomServerPort; @Test public void testGetPrintableDocumentSE() { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("siteId", "123456789"); RestTemplate restTemplate = new RestTemplate(); Invoice invoice = Invoice.builder().invoiceNumber(1234).language("SE").build(); try { RequestEntity<Invoice> requestEntity = new RequestEntity<>(invoice, requestHeaders, HttpMethod.POST, new URI("")); ResponseEntity<Resource> responseEntity = restTemplate.exchange( "http://localhost:" + randomServerPort + "/print/invoice", HttpMethod.POST, requestEntity, Resource.class); } catch (Exception e) { throw new RuntimeException(e); } } }
问题原因
- 端口注入失败:错误日志显示请求端口为
0,说明@LocalServerPort未正确注入随机端口,核心原因是Spring Boot应用在GitHub Actions环境中启动失败,未完成端口分配。 - RequestEntity构造不合理:使用空
URI构造RequestEntity,可能与exchange方法中指定的完整URL产生解析冲突。 - CI环境资源限制:GitHub Actions runner资源有限,应用启动超时,未完成初始化就执行测试,导致端口未就绪。
解决办法
1. 替换为TestRestTemplate(推荐)
Spring Boot提供的TestRestTemplate会自动适配随机端口,无需手动拼接URL,彻底避免端口注入问题:
@ExtendWith({SpringExtension.class}) @SpringBootTest(classes = {PrintingApp.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class PrintingAppTest { @Autowired private TestRestTemplate testRestTemplate; @Test public void testGetPrintableDocumentSE() { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("siteId", "123456789"); Invoice invoice = Invoice.builder().invoiceNumber(1234).language("SE").build(); HttpEntity<Invoice> requestEntity = new HttpEntity<>(invoice, requestHeaders); ResponseEntity<Resource> responseEntity = testRestTemplate.exchange( "/print/invoice", HttpMethod.POST, requestEntity, Resource.class); } }
2. 修复RequestEntity构造逻辑
若坚持使用原生RestTemplate,不要用空URI构造RequestEntity,改用HttpEntity传递请求体和头信息:
// 替换原RequestEntity相关代码 HttpEntity<Invoice> requestEntity = new HttpEntity<>(invoice, requestHeaders); ResponseEntity<Resource> responseEntity = restTemplate.exchange( "http://localhost:" + randomServerPort + "/print/invoice", HttpMethod.POST, requestEntity, Resource.class);
3. 排查应用启动问题
- 查看GitHub Actions流水线的应用启动日志,检查是否存在依赖缺失、配置错误或启动异常。
- 确保CI环境的JDK版本、依赖库版本与本地完全一致。
4. 增加测试超时时间
修改pom.xml中的maven-surefire-plugin配置,延长测试进程超时时间,给应用足够的启动时间:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds> </configuration> </plugin>
内容的提问来源于stack exchange,提问作者Joakim Gradin
相关产品推荐
相关产品推荐

