使用属性 server.port=0 运行 spock 测试时如何找到 Spring Boot 容器的端口

Posted

技术标签:

【中文标题】使用属性 server.port=0 运行 spock 测试时如何找到 Spring Boot 容器的端口【英文标题】:How to find port of Spring Boot container when running a spock test using property server.port=0 【发布时间】:2014-08-29 21:02:51 【问题描述】:

鉴于application.properties中的此条目:

server.port=0

这会导致 Spring Boot 选择一个随机可用端口,并使用 spock 测试 Spring Boot Web 应用程序,spock 代码如何知道要访问哪个端口?

像这样正常注入:

@Value("$local.server.port")
int port;

不适用于 spock。

【问题讨论】:

【参考方案1】:

您可以使用以下代码找到端口:

int port = context.embeddedServletContainer.port

对于那些对 java 等价物感兴趣的人是:

int port = ((TomcatEmbeddedServletContainer)((AnnotationConfigEmbeddedWebApplicationContext)context).getEmbeddedServletContainer()).getPort();

这是一个可以扩展的抽象类,它封装了 Spring Boot 应用程序的初始化并确定了端口:

abstract class SpringBootSpecification extends Specification 

    @Shared
    @AutoCleanup
    ConfigurableApplicationContext context

    int port = context.embeddedServletContainer.port

    void launch(Class clazz) 
        Future future = Executors.newSingleThreadExecutor().submit(
                new Callable() 
                    @Override
                    public ConfigurableApplicationContext call() throws Exception 
                        return (ConfigurableApplicationContext) SpringApplication.run(clazz)
                    
                )
        context = future.get(20, TimeUnit.SECONDS);
    

你可以这样使用:

class MySpecification extends SpringBootSpecification 
    void setupSpec() 
        launch(MyLauncher.class)
    

    String getBody(someParam) 
        ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:$port/somePath/$someParam", String.class)
        return entity.body;
    

【讨论】:

【参考方案2】:

只要您正确配置了规范类并在类路径中有spock-spring,注入将与 Spock 一起使用。有一个limitation in Spock Spring,这意味着如果您使用@SpringApplicationConfiguration,它将不会引导您的引导应用程序。您需要使用@ContextConfiguration 并手动配置它。详情请见this answer。

问题的第二部分是您不能为@Value 使用GString。您可以转义 $,但使用单引号更容易:

@Value('$local.server.port')
private int port;

把这些放在一起,你会得到一个看起来像这样的规范:

@ContextConfiguration(loader = SpringApplicationContextLoader, classes = SampleSpockTestingApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port=0")
class SampleSpockTestingApplicationSpec extends Specification 

    @Value("\$local.server.port")
    private int port;

    def "The index page has the expected body"() 
        when: "the index page is accessed"
        def response = new TestRestTemplate().getForEntity(
            "http://localhost:$port", String.class);
        then: "the response is OK and the body is welcome"
        response.statusCode == HttpStatus.OK
        response.body == 'welcome'
    

还要注意使用@IntegrationTest("server.port=0") 来请求使用随机端口。这是在application.properties 中配置它的一个不错的选择。

【讨论】:

@SpringApplicationConfiguration 似乎正在使用 Spock 1.0。 安迪的答案应该被标记为真正的答案。他使用@Value 字符串获取端口号的解决方案更加优雅。 顺便说一句,@andy-wilkinson,spock-spring 现在支持 @SpringBootTest 作为单个注释,而不必组合 @ContextConfiguration@WebAppConfiguration@IntegrationTests。所以你所要做的就是:@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)【参考方案3】:

你也可以这样做:

@Autowired
private org.springframework.core.env.Environment springEnv;
...
springEnv.getProperty("server.port");

【讨论】:

以上是关于使用属性 server.port=0 运行 spock 测试时如何找到 Spring Boot 容器的端口的主要内容,如果未能解决你的问题,请参考以下文章

属性配置文件详解

属性配置文件详解

属性配置文件详解

SpringBoot 配置文件说明

使用 application.properties 中配置的属性,举例:@Value("${server.port}")

Spring Cloud Spring Boot mybatis分布式微服务云架构属性配置文件详解