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

Boh*_*ian 7 testing port spock spring-boot

鉴于此条目application.properties:

server.port=0
Run Code Online (Sandbox Code Playgroud)

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

正常注射如下:

@Value("${local.server.port}")
int port;
Run Code Online (Sandbox Code Playgroud)

不适用于spock.

Boh*_*ian 12

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

int port = context.embeddedServletContainer.port
Run Code Online (Sandbox Code Playgroud)

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

int port = ((TomcatEmbeddedServletContainer)((AnnotationConfigEmbeddedWebApplicationContext)context).getEmbeddedServletContainer()).getPort();
Run Code Online (Sandbox Code Playgroud)

这是一个可以扩展的抽象类,它包装了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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以这样使用:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*son 8

注入将与Spock一起使用,只要您已正确配置spec类并具有spock-spring类路径.Spock Spring存在一个限制,这意味着如果您使用它,它将不会引导您的Boot应用程序@SpringApplicationConfiguration.您需要@ContextConfiguration手动使用和配置它.有关详细信息,请参阅此答案.

问题的第二部分是你不能使用GString @Value.你可以逃脱$,但使用单引号更容易:

@Value('${local.server.port}')
private int port;
Run Code Online (Sandbox Code Playgroud)

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

@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'
    }
}
Run Code Online (Sandbox Code Playgroud)

另请注意使用@IntegrationTest("server.port=0")请求随机端口.这是配置它的一个很好的替代方案application.properties.