Remplacer les paramètres par défaut de l'application Spring-Boot application.properties dans Junit Test

198

J'ai une application Spring-Boot où les propriétés par défaut sont définies dans un application.propertiesfichier dans le chemin de classe (src / main / resources / application.properties).

Je voudrais remplacer certains paramètres par défaut dans mon test JUnit avec des propriétés déclarées dans un test.propertiesfichier (src / test / resources / test.properties)

J'ai habituellement une classe de configuration dédiée pour mes tests Junit, par exemple

package foo.bar.test;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

}

J'ai d'abord pensé que l'utilisation @PropertySource("classpath:test.properties")de la classe TestConfig ferait l'affaire, mais ces propriétés n'écraseront pas les paramètres application.properties (voir le document de référence Spring-Boot - 23. Externalized Configuration ).

Ensuite, j'ai essayé d'utiliser -Dspring.config.location=classpath:test.propertieslors de l'appel du test. Cela a réussi - mais je ne veux pas définir cette propriété système pour chaque exécution de test. Je l'ai donc mis dans le code

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

  static {
    System.setProperty("spring.config.location", "classpath:test.properties");
  }

}

qui malheureusement n'a de nouveau pas réussi.

Il doit y avoir une solution simple sur la façon de remplacer les application.propertiesparamètres dans les tests JUnit avec ce test.propertiesque j'ai dû ignorer.

FrVaBe
la source
Si vous devez configurer seulement quelques propriétés, vous pouvez utiliser la nouvelle annotation @DynamicPropertySource. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Réponses:

293

Vous pouvez utiliser @TestPropertySourcepour remplacer les valeurs dans application.properties. De son javadoc:

les sources de propriétés de test peuvent être utilisées pour remplacer de manière sélective les propriétés définies dans les sources de propriétés système et d'application

Par exemple:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {

}
Andy Wilkinson
la source
2
C'est tout. Merci. Malheureusement, cela ne fonctionne pas lorsqu'il est utilisé sur ExampleApplication.class, je dois donc le définir sur chaque classe de test. Est-ce correct?
FrVaBe
1
Il doit aller quelque part dans la hiérarchie de la classe de test, c'est-à-dire que vous pouvez utiliser une superclasse commune pour la configurer sur un certain nombre de classes de test différentes.
Andy Wilkinson
64
Notez également que @TestPropertySourcepeut accepter un propertiesargument pour remplacer certaines propriétés en ligne, par exemple @TestPropertySource(properties = "myConf.myProp=valueInTest"), il est utile dans le cas où vous ne voulez pas un fichier de propriété totalement nouveau.
dyng
2
Vous pouvez spécifier plusieurs fichiers dans un tableau, ainsi que des fichiers sur le système de fichiers (mais n'oubliez pas qu'ils peuvent ne pas fonctionner sur le serveur CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam
8
Notez que cela @SpringApplicationConfigurationest déjà obsolète et que vous devriez utiliser@SpringBootTest
mrkernelpanic
74

Spring Boot se charge automatiquement src/test/resources/application.propertiessi les annotations suivantes sont utilisées

@RunWith(SpringRunner.class)
@SpringBootTest

Donc, renommez- test.propertiesle application.propertiespour utiliser la configuration automatique.

Si vous * seulement * devez charger le fichier de propriétés (dans l'environnement), vous pouvez également utiliser ce qui suit, comme expliqué ici

@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) 

[ Mise à jour: remplacement de certaines propriétés pour les tests ]

  1. Ajouter src/main/resources/application-test.properties.
  2. Annoter la classe de test avec @ActiveProfiles("test").

Cela se charge application.properties, puis les application-test.properties propriétés dans le contexte d'application pour le scénario de test, selon les règles définies ici .

Démo - https://github.com/mohnish82/so-spring-boot-testprops

Mohnish
la source
1
Je ne sais pas si c'est une bonne idée d'avoir deux application.propertiesfichiers sur le chemin de classe (un en src/main/resourceset un en src/test/resources). Qui garantit que les deux seront prises et laquelle sera prise en premier?
FrVaBe
3
@FrVaBe Spring va le garantir! Les propriétés du profil principal sont toujours chargées. Ensuite, pendant la phase de test, les propriétés du test sont chargées, ajoutant / remplaçant les propriétés nouvelles / existantes. Si vous ne le faites pas comme garder deux fichiers avec le même nom, vous pouvez ajouter application-test.propertiesà src/main/resourceset préciser testque le profil actif dans le cas de test.
Mohnish
7
Le printemps ne donne aucune garantie. L'outil de construction utilisera les ressources de test au profit des principales ressources pendant les tests. Mais dans le cas d'un test application.properties, le principal application.properties sera ignoré. Ce n'est pas ce que je veux car la principale contient plusieurs valeurs par défaut utiles et je n'ai besoin que de remplacer certaines d'entre elles pendant le test (et je ne veux pas dupliquer tout le fichier dans la section test). Voyez ici .
FrVaBe
6
Vous avez raison, seules les propriétés définies dans src/test/resources/application.propertiessont chargées pendant la phase de test, src/main/resources/application.propertiesest ignorée.
Mohnish
11
Si vous n'utilisez pas de profils jusqu'à présent, vous n'avez pas besoin d'un profil "test" dédié. Nommez simplement vos propriétés de test application-default.propertieset elles seront prises en compte car vous exécutez automatiquement le profil "par défaut" (s'il n'est pas déclaré autre).
FrVaBe
65

Vous pouvez également utiliser des méta-annotations pour externaliser la configuration. Par exemple:

@RunWith(SpringJUnit4ClassRunner.class)
@DefaultTestAnnotations
public class ExampleApplicationTests { 
   ...
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public @interface DefaultTestAnnotations { }
Rob Winch
la source
21

Une autre approche appropriée pour remplacer quelques propriétés dans votre test, si vous utilisez des @SpringBootTestannotations:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
la source
1
ne SpringBootTestcharger le fichier application.properties?
TuGordoBello
8

TLDR:

Donc, ce que j'ai fait, c'est d'avoir la norme src/main/resources/application.propertieset aussi un src/test/resources/application-default.propertiesendroit où je remplace certains paramètres pour TOUS mes tests.

Histoire entière

J'ai rencontré le même problème et n'utilisais pas de profils non plus jusqu'à présent. Cela semblait gênant de devoir le faire maintenant et de se souvenir d'avoir déclaré le profil - ce qui peut être facilement oublié.

L'astuce consiste à tirer parti du fait qu'un profil spécifique application-<profile>.propertiesremplace les paramètres du profil général. Voir https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
la source
3

Explication simple:

Si vous êtes comme moi et que vous avez le même application.propertiesdans src/main/resourceset src/test/resources, et vous vous demandez pourquoi le application.propertiesdans votre dossier de test ne remplace pas le application.propertiesdans vos ressources principales, lisez la suite ...

Si vous avez application.propertiessous src/main/resourceset le même application.propertiessous src/test/resources, qui application.propertiesest ramassé, dépend de la façon dont vous exécutez vos tests . Le dossier la structure src/main/resources et src/test/resources, est une convention d' architecture Maven, donc si vous exécutez votre test comme mvnw testou même gradlew test, l' application.propertiesen src/test/resourcesaurez ramassé, comme épreuve classpath précédera principale classpath. Mais, si vous exécutez votre test comme Run as JUnit Testdans Elipse / STS, l' application.propertiesen ne src/main/resourcessera pas repris, comme principaux précède classpath essai classpath.

Vous pouvez le vérifier en ouvrant le Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line" .

Vous verrez quelque chose comme:

XXXbin \ javaw.exe -ea -Dfile.encoding = UTF-8 -classpath XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ main; XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ test;

Voyez-vous que \ main vient en premier, puis \ test ? Bon, tout est question de chemin de classe :-)

À votre santé

jumping_monkey
la source
1
I just configured min as the following :

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console


# changing the name of my data base for testing
spring.datasource.url= jdbc:h2:mem:mockedDB
spring.datasource.username=sa
spring.datasource.password=sa



# in testing i don`t need to know the port

#Feature that determines what happens when no accessors are found for a type
#(and there are no annotations to indicate it is meant to be serialized).
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false`enter code here`
Hilal Aissani
la source
1

Si vous utilisez Spring 5.2.5 et Spring Boot 2.2.6 et souhaitez remplacer uniquement quelques propriétés au lieu du fichier entier. Vous pouvez utiliser la nouvelle annotation: @DynamicPropertySource

@SpringBootTest
@Testcontainers
class ExampleIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>();

    @DynamicPropertySource
    static void neo4jProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
    }
}
Felipe Desiderati
la source
0

Sinon, nous pouvons changer le nom du configurateur de propriétés par défaut, définir la propriété spring.config.name=test, puis avoir la ressource de chemin de classe dont src/test/test.propertiesnotre instance native org.springframework.boot.SpringApplicationsera automatiquement configurée à partir de ce test.properties séparé, en ignorant les propriétés de l'application;

Avantage: auto-configuration des tests;

Inconvénient: exposition de la propriété "spring.config.name" au niveau de la couche CI

réf: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

spring.config.name = application # Nom du fichier de configuration

D. Soloviev
la source
5
Ignorer application.propertiesn'est pas une option pour moi car je veux seulement remplacer certaines des valeurs de configuration d'origine dans le test.
FrVaBe
J'ai cherché un moyen d'avoir un seul test qui ne charge pas le src / main / resources / application.properties et c'est tout. Créez un fichier: src / test / resources / empty.properties et ajoutez l'annotation aux tests qui doivent ignorer les propriétés principales. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo
Comment définir une valeur de propriété spécifique pour chaque méthode de test Junit?
Nicolas
0

Vous pouvez également créer un fichier application.properties dans src / test / resources où vos JUnits sont écrites.

PragmaticFire
la source
Comment cela aide-t-il? ^^
jumping_monkey