簡體   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