Spring REST应用Maven集成测试:@LocalManagementPort端口为0问题排查
我要给Spring REST应用的Maven构建添加集成测试,测试类用Groovy编写,继承自基于spock.lang.Specification的抽象基类。
基类代码如下:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @Testcontainers abstract class Base extends Specification { ... }
测试类代码如下:
class SomeTestIT extends Base { @LocalManagementPort private int localManagementPort private RequestSpecification reqSpec def setup() { reqSpec = new RequestSpecBuilder() .setPort(localManagementPort) .build() } ... }
测试运行时抛出IllegalArgumentException: Port must be greater than 0异常,该异常来自io.restassured.internal.RequestSpecificationImpl,原因是@LocalManagementPort注解的字段值为0,该注解依赖local.management.port属性。我尝试过设置系统属性和Spring Boot配置属性,但问题未解决,请问如何获取非零的端口值?
使用的组件版本:
- Apache Maven 3.8.7
- Java 17.0.6(厂商:Eclipse Adoptium)
- Groovy 3.0.13
- gmavenplus-plugin: 2.1.0
- springframework.boot:spring-boot-test: 2.7.7
- spockframework:spock-core: 2.3.groovy-4.0
1. 确认管理端口配置有效性
先确保Spring Boot应用已开启Actuator并配置管理端口,在测试环境配置文件(如application-test.properties)中添加:
# 指定固定端口或设为0随机分配 management.server.port=8081 # 按需暴露端点,至少保证测试需要的端点可访问 management.endpoints.web.exposure.include=health,info
2. 调整端口注入与初始化时机
Spock的setup()方法执行时,Spring上下文可能未完成@LocalManagementPort的注入,导致端口值为0。可以改用@PostConstruct注解延迟初始化逻辑,确保端口已注入:
class SomeTestIT extends Base { @LocalManagementPort private int localManagementPort private RequestSpecification reqSpec @PostConstruct void initRequestSpec() { reqSpec = new RequestSpecBuilder() .setPort(localManagementPort) .build() } ... }
3. 修正Spock与Groovy版本兼容性
当前使用的spock-core:2.3.groovy-4.0是针对Groovy 4.x的,而你的Groovy版本是3.0.13,版本不匹配可能导致Spring注解注入异常。将Spock版本调整为适配Groovy 3.x的版本:
<!-- pom.xml中更新Spock依赖 --> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>2.3-groovy-3.0</version> <scope>test</scope> </dependency>
4. 手动从Spring Environment获取端口
如果注解注入仍有问题,可以通过Spring Environment直接读取local.management.port属性:
class SomeTestIT extends Base { @Autowired private Environment environment private RequestSpecification reqSpec def setup() { Integer managementPort = environment.getProperty("local.management.port", Integer.class) reqSpec = new RequestSpecBuilder() .setPort(managementPort) .build() } ... }
5. 检查@SpringBootTest配置
确保@SpringBootTest的webEnvironment配置未覆盖管理端口逻辑,若使用DEFINED_PORT,需保证管理端口配置未被测试代码或系统属性意外重置为0。若需要随机端口,将management.server.port=0写入测试配置,Spring会自动分配可用端口并更新local.management.port属性。
内容的提问来源于stack exchange,提问作者Kérdezősködő Indián

