web-dev-qa-db-ja.com

スプリングブートテストでワイヤーモックランダムポートを使用してプロパティを設定する

Wiremockを使用して外部サービスをモックするSpring Bootテストがあります。並列ビルドとの競合を回避するために、wiremockに固定ポート番号を設定したくないので、動的ポート構成に依存したいと思います。

アプリケーションはプロパティ(external.baseUrl)application.ymlで設定します(src/test/resourcesの下)。しかし、それをプログラムでオーバーライドする方法は見つかりませんでした。私はこのようなものを試しました:

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

しかし、それは機能せず、代わりにapplication.ymlの値が使​​用されました。私が調べた他のすべてのソリューションは、静的な値(たとえば、いくつかの注釈)でプロパティをオーバーライドしますが、テストが実行されるまで、ワイヤモックポートの値はわかりません。

説明:

スプリングブートとワイヤモックの両方がランダムなポートで実行されます。 それは問題なく、両方のポートの値を取得する方法を知っています。ただし、wiremockは外部サービスをモックすることになっているため、アプリケーションに到達する方法をアプリケーションに通知する必要があります。私はexternal.baseUrlプロパティ。テストで設定する値は、もちろん、Wirmockポート番号によって異なります。 私の問題は、スプリングブートテストでプログラムによってプロパティを設定する方法です

7

Spring Cloud Contract Wiremock の使用を検討してください

プロパティ/ yamlファイルにランダムなポートを設定するために${wiremock.port}を指定できるJUnitルールビルダーがすでにあります

または、WireMockRestServiceServerを使用してWireMockをRestTemplateにバインドできるため、テストでURLをオーバーライドする必要もありません。

5
Dagon

アプリケーションが作成され、すべてのBeanがすでに構成されている場合にのみテストが実行されるため、Spring Boot統合テストでプロパティをオーバーライドする方法が見つかりませんでした。

回避策として、@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がテストで定義されたものと効果的に置き換えられ、Wirmockの正しいポート番号が設定されました。

この構成をピックアップするには、このクラスをテストアノテーションに追加する必要がありました。

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

静的なWiremock APIを使用していることに注意してください。モックする必要がある外部サービスがいくつかあるからです。異なるBeanの作成方法は、それぞれの設計方法によって異なることに注意してください。

5

Application.propertiesでプロパティ置換を使用します。

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

これには、SpringBootTestが初期化される前にwiremock.server.portプロパティを設定する必要があります。これは、テストクラスに@AutoConfigureWireMockアノテーションを追加することで実現できます。

3
user3302637

https://stackoverflow.com/a/48859553/30968 (つまり、wiremock.port)に記載されているプロパティ名は、少なくともSpring Cloud契約バージョン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がランダムに選択されたワイヤモックポートに設定されていることを確認できます。

@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")));
    }
}
2

Spring Bootアプリの起動時にプログラムでプロパティを変更するために使用するアプローチは、カスタム値をアプリケーションのメインエントリポイントString[] argsに渡すことです。これは、システムプロパティ、YML、その他の構成ファイルなど、他のすべての手段を上書きする効果があります。

これが です:

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

Spring Bootアプリ(テスト用)を起動し、必要な値で静的メソッドまたはカスタムAPIを公開するのは簡単です。

そして、Wirmockポートの価値があれば、簡単です。次に例を示します。 PaymentServiceContractTest.Java

追伸空手(上記で使用しているオープンソースのテスト例)は WireMockの新しい代替手段 です。確認してください;)

0
Peter Thomas

これはどうですか:

@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);
    }
}
0
luboskrnac