繁体   English   中英

在 spring 启动测试中使用 wiremock 随机端口设置属性

[英]Set property with wiremock random port in spring boot test

我有一个 Spring 启动测试,它使用 wiremock 来模拟外部服务。 为了避免与并行构建发生冲突,我不想为 wiremock 设置固定端口号,而是希望依赖其动态端口配置。

该应用程序使用在 application.yml(在 src/test/resources 下)中设置的属性 ( external.baseUrl )。 但是我没有找到以编程方式覆盖它的方法。 我试过这样的事情:

    WireMockServer wireMockServer = new WireMockServer();
    wireMockServer.start();
    WireMock mockClient = new WireMock("localhost", wireMockServer.port());
    System.setProperty("external.baseUrl", "http://localhost:" + wireMockServer.port());

但它不起作用,而是使用了 application.yml 中的值。 我看过的所有其他解决方案都使用 static 值覆盖该属性(例如在某些注释中),但在测试运行之前我不知道 wiremock 端口的值。

澄清:

spring boot 和 wiremock 都在随机端口上运行。 很好,我知道如何获得两个端口的值 然而,wiremock 应该模拟外部服务,我需要告诉我的应用程序如何访问它。 我使用external.baseUrl属性执行此操作。 我想在测试中设置的值当然取决于 wiremock 端口号。 我的问题只是如何以编程方式在 spring 启动测试中设置属性

我找不到在Spring Boot集成测试中覆盖属性的方法,因为测试仅在创建应用程序并且已经配置了所有bean之后运行。

作为解决方法,我在测试中添加了@TestConfiguration来替换应用程序中的bean:

private static WireMockServer wireMockServer1 = getWireMockServer();
private static WireMockServer wireMockServer2 = getWireMockServer();
private static WireMockServer wireMockServer3 = getWireMockServer();

private static WireMockServer getWireMockServer() {
    final WireMockServer wireMockServer = new WireMockServer(options().dynamicPort());
    wireMockServer.start();
    return wireMockServer;
}

@TestConfiguration
static class TestConfig {
    @Bean
    @Primary
    public BeanUsingAProperty1 getBean1() {
        BeanUsingAProperty myBean = new BeanUsingAProperty();
        myBean.setPort(wireMockServer.port());
        return myBean;
    }

    @Bean
    @Primary
    public BeanUsingAProperty2 getBean2() {
        String baseUrl = "http://localhost:" + wireMockServer2.port();
        return new BeanUsingAProperty2(baseUrl);
    }

    @Bean
    @Primary
    public BeanUsingAProperty3 getBean3() {
        String baseUrl = "http://localhost:" + wireMockServer3.port() + "/request";
        return new BeanUsingAProperty3(new RestTemplate(), baseUrl, "someOtherParameter");
    }
}

这有效地将BeanUsingAProperty替换为测试中定义的BeanUsingAProperty ,以便它具有Wiremock的正确端口号。

要获取此配置,我必须在测试注释中添加此类

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {
    MySpringBootApplication.class, MyIntegrationTest.TestConfig.class })

请注意,我使用非静态Wiremock API,因为我有几个这样的外部服务,每个都需要被模拟。 请注意,根据每个bean的设计方式,如何构建不同的bean。

考虑使用Spring Cloud Contract Wiremock

已有一个JUnit Rule构建器允许指定${wiremock.port}来设置property / yaml文件中的随机端口

或者您可以使用WireMockRestServiceServer将WireMock绑定到RestTemplate这样您甚至不需要覆盖测试中的URL。

在application.properties中使用属性替换:

external.baseUrl=http://exampleUrl:${wiremock.server.port}

这需要在SpringBootTest初始化之前设置wiremock.server.port属性,这可以通过将@AutoConfigureWireMock注释添加到测试类来实现。

https://stackoverflow.com/a/48859553/309683 (即wiremock.port )中提到的属性名称不正确,至少从Spring Cloud Contract 2.1.2.RELEASE

1.工作实例

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureWireMock(port = 0)
public class PortServiceTest {

    @Autowired
    private Environment environment;

    @Test
    public void shouldPopulateEnvironmentWithWiremockPort() {
        assertThat(environment.containsProperty("wiremock.server.port")).isTrue();
        assertThat(environment.getProperty("wiremock.server.port")).matches("\\d+");
    }

}

2.其他WireMock属性

除了wiremock.server.port@AutoConfigureWireMock使用其他一些属性填充环境:

  1. wiremock.server.https-port
  2. wiremock.server.stubs[]
  3. wiremock.server.files[]

3. Gradle依赖项

要在基于Gradle的项目中使用Spring Cloud Contract WireMock,请将以下依赖项添加到项目中:

testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock:${version}'

4.在application.yaml文件中使用

如果您配置测试application.yaml文件,如下所示:

sample:
  port: ${wiremock.server.port}

并定义以下bean:

@Component
@ConfigurationProperties(prefix = "sample")
@Data
public class PortProperties {
    private Integer port;
}

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PortService {
    private final PortProperties config;

    public Integer getPort() {
        return config.getPort();
    }
}

您可以验证sample.port是否设置为随机选择的wiremock端口:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureWireMock(port = 0)
public class PortServiceTest {
    @Autowired
    private Environment environment;

    @Autowired
    private PortService portService;

    @Test
    public void shouldReturnWireMockPort() {
        assertThat(portService.getPort())
                .isNotNull()
                .isEqualTo(Integer.parseInt(environment.getProperty("wiremock.server.port")));
    }
}

那这个呢:

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
class YourTestClass {
    @LocalServerPort
    int port;

    public void test() {
        WireMockServer wireMockServer = new WireMockServer(port);
        wireMockServer.start();
        WireMock mockClient = new WireMock("localhost", port);
    }
}

我在启动Spring Boot应用程序时用于以编程方式更改属性的方法是将自定义值传递到应用程序主入口点String[] args。 这将具有覆盖所有其他方式的效果,例如系统属性,YML或其他配置文件。

这是一个例子

String[] args = new String[]{"--my.prop=foo"};
SpringApplication.run(Application.class, args);

您可以轻松地公开静态方法或自定义API,以启动Spring Boot应用程序(用于测试)并使用您想要的值。

然后,一旦你拥有了线索端口的价值 - 事情很简单。 这是一个例子: PaymentServiceContractTest.java

PS Karate(我上面使用的开源测试示例)是WireMock新替代品 ,请查看它;)

当你使用 org.springframework.cloud:spring-cloud-contract-wiremock 依赖时,如果你喜欢注释,你可以添加@AutoConfigureWireMock(port = Options.DYNAMIC_PORT)

你是如何阅读external.baseUrl 如果您使用的是@Value annotated属性,则可以在设置模拟服务器后使用ReflectionTestUtils设置端口。

ReflectionTestUtils.setField(yourTestClass, "youPort",  wireMockServer.port());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM