web-dev-qa-db-fra.com

Définir la propriété avec le port aléatoire wiremock dans le test de démarrage du printemps

J'ai un test Spring Boot qui utilise wiremock pour se moquer d'un service externe. Afin d'éviter les conflits avec les versions parallèles, je ne souhaite pas définir de numéro de port fixe pour wiremock et je souhaite pouvoir compter sur sa configuration de port dynamique.

L'application utilise une propriété (external.baseUrl) définie dans le fichier application.yml (sous src/test/resources). Cependant, je n'ai pas trouvé le moyen de remplacer cela par programme. J'ai essayé quelque chose comme ça:

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

mais cela n'a pas fonctionné et la valeur dans application.yml a été utilisée à la place. Toutes les autres solutions que j'ai examinées remplacent la propriété par une valeur statique (par exemple, dans certaines annotations), mais je ne connais pas la valeur du port wiremock tant que le test n'est pas exécuté.

Clarification:

Spring Boot et wiremock fonctionnent tous deux sur des ports aléatoires. C'est bien et je sais comment obtenir la valeur des deux ports. Cependant, wiremock est censé se moquer d'un service externe et je dois dire à mon application comment l'atteindre. Je le fais avec la propriété external.baseUrl. La valeur que je veux définir dans mon test dépend bien sûr du numéro de port wiremock. Mon problème est simplement comment définir par programme une propriété dans un test de démarrage de printemps .

5
bangnab

Envisagez d'utiliser Spring Cloud Contract Wiremock

Il existe déjà un générateur de règles JUnit qui permet de spécifier ${wiremock.port} .__ pour définir un port aléatoire dans les fichiers de propriété/yaml

Ou vous pouvez utiliser WireMockRestServiceServer pour lier wiremock à votre RestTemplate afin que vous n'ayez même pas besoin de remplacer l'URL dans vos tests

2
Dagon

Je ne pouvais pas trouver un moyen de remplacer les propriétés dans un test d'intégration Spring Boot, car le test n'est exécuté qu'après la création de l'application et la configuration de tous les beans.

Pour contourner le problème, j’ai ajouté un @TestConfiguration au test pour remplacer les beans dans l’application:

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

Ceci a effectivement remplacé la BeanUsingAProperty par celle définie dans le test, de sorte qu'elle ait le numéro de port correct pour Wiremock.

Pour que cette configuration soit prise en compte, je devais ajouter cette classe dans l'annotation de test.

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

Notez que j'utilise l'API Wiremock non statique, car plusieurs services externes de ce type doivent être simulés. Notez que la manière dont les différents haricots sont construits varie en fonction de la conception de chacun.

5
bangnab

Utilisez la substitution de propriété dans votre application.properties:

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

Cela nécessite la définition de la propriété wiremock.server.port avant l'initialisation de SpringBootTest, ce qui peut être obtenu en ajoutant l'annotation @AutoConfigureWireMock à votre classe de test.

1
user3302637

L’approche que j’utilise pour modifier par programme une propriété lors du démarrage d’une application Spring Boot consiste à transmettre la valeur personnalisée au point d’entrée principal de l’application String[] args. Cela aura pour effet de supplanter tous les autres moyens tels que les propriétés système, YML ou d'autres fichiers de configuration.

Voici un exemple :

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

Il vous sera facile d’exposer une méthode statique ou une API personnalisée qui lance l’application Spring Boot (à des fins de test) et avec la valeur souhaitée.

Et puis, une fois que vous avez la valeur du port wiremock, tout est facile. Voici un exemple: PaymentServiceContractTest.Java

P.S. Karate (les exemples de tests open-source que j'utilise ci-dessus) est une nouvelle alternative à WireMock , vérifiez-le;)

0
Peter Thomas

Et ça:

@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