Überschreiben Sie die Standardeinstellungen für Spring-Boot application.properties in Junit Test

198

Ich habe eine Spring-Boot-Anwendung, in der die Standardeigenschaften in einer application.propertiesDatei im Klassenpfad festgelegt sind (src / main / resources / application.properties).

Ich möchte einige Standardeinstellungen in meinem JUnit-Test mit Eigenschaften überschreiben, die in einer test.propertiesDatei deklariert sind (src / test / resources / test.properties).

Normalerweise habe ich eine spezielle Konfigurationsklasse für meine Junit-Tests, z

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 {

}

Ich dachte zuerst, dass die Verwendung @PropertySource("classpath:test.properties")in der TestConfig-Klasse den Trick machen würde, aber diese Eigenschaften überschreiben die Einstellungen von application.properties nicht (siehe Spring-Boot-Referenzdokument - 23. Externalisierte Konfiguration ).

Dann habe ich versucht, -Dspring.config.location=classpath:test.propertiesbeim Aufrufen des Tests zu verwenden. Das war erfolgreich - aber ich möchte diese Systemeigenschaft nicht für jede Testausführung festlegen. Also habe ich es in den Code eingefügt

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

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

}

was leider wieder nicht erfolgreich war.

Es muss eine einfache Lösung geben, wie application.propertiesEinstellungen in JUnit-Tests überschrieben werden können test.properties, die ich übersehen haben muss.

FrVaBe
quelle
Wenn Sie nur einige Eigenschaften konfigurieren müssen, können Sie die neue Annotation @DynamicPropertySource verwenden. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Antworten:

293

Sie können @TestPropertySourceWerte in überschreiben application.properties. Aus seinem Javadoc:

Testeigenschaftsquellen können verwendet werden, um Eigenschaften, die in System- und Anwendungseigenschaftsquellen definiert sind, selektiv zu überschreiben

Beispielsweise:

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

}
Andy Wilkinson
quelle
2
Das ist es. Vielen Dank. Leider funktioniert es nicht, wenn es in der ExampleApplication.class verwendet wird, daher muss ich es für jede Testklasse festlegen. Ist das richtig?
FrVaBe
1
Es muss irgendwo in der Hierarchie der Testklasse stehen, dh Sie können eine gemeinsame Oberklasse verwenden, um es für eine Reihe verschiedener Testklassen zu konfigurieren.
Andy Wilkinson
64
Beachten Sie auch, dass @TestPropertySourceein propertiesArgument zum Überschreiben einiger Eigenschaften inline akzeptiert werden kann. Dies ist beispielsweise @TestPropertySource(properties = "myConf.myProp=valueInTest")nützlich, wenn Sie keine brandneue Eigenschaftendatei möchten.
Dyng
2
Sie können mehrere Dateien in einem Array sowie Dateien im Dateisystem angeben (aber denken Sie daran, dass sie möglicherweise nicht auf dem CI-Server funktionieren):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam
8
Beachten Sie, dass dies @SpringApplicationConfigurationbereits veraltet ist und Sie verwenden sollten@SpringBootTest
mrkernelpanic
74

Spring Boot wird automatisch geladen src/test/resources/application.properties, wenn die folgenden Anmerkungen verwendet werden

@RunWith(SpringRunner.class)
@SpringBootTest

Benennen Sie also test.propertiesum application.properties, um die automatische Konfiguration zu verwenden.

Wenn Sie * nur * die Eigenschaftendatei (in die Umgebung) laden müssen, können Sie auch Folgendes verwenden, wie hier erläutert

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

[ Update: Überschreiben bestimmter Eigenschaften zum Testen ]

  1. Hinzufügen src/main/resources/application-test.properties.
  2. Testklasse mit kommentieren @ActiveProfiles("test").

Dadurch werden die Eigenschaften für den Testfall gemäß den hier definierten Regeln geladen application.propertiesund anschließend application-test.properties in den Anwendungskontext übernommen .

Demo - https://github.com/mohnish82/so-spring-boot-testprops

Mohnish
quelle
1
Ich bin mir nicht sicher, ob es eine gute Idee ist, zwei application.propertiesDateien im Klassenpfad zu haben (eine in src/main/resourcesund eine in src/test/resources). Wer garantiert, dass beide genommen werden und welche zuerst genommen werden?
FrVaBe
3
@FrVaBe Spring wird es garantieren! Hauptprofileigenschaften werden immer geladen. Während der Testphase werden dann Testeigenschaften geladen, wobei neue / vorhandene Eigenschaften hinzugefügt / überschrieben werden. Wenn Sie nicht möchten, dass zwei Dateien denselben Namen haben, können Sie application-test.propertiesim Testfall das aktive Profil hinzufügen src/main/resourcesund angeben test.
Mohnish
7
Der Frühling gibt keine Garantie. Das Build-Tool verwendet während der Tests die Testressourcen zugunsten der Hauptressourcen. Bei einer Testanwendung werden jedoch die Hauptanwendungseigenschaften ignoriert. Das ist nicht das, was ich will, weil der Hauptwert mehrere nützliche Standardwerte enthält und ich nur einige davon während des Tests überschreiben muss (und ich möchte nicht die gesamte Datei im Testabschnitt duplizieren). Siehe hier .
FrVaBe
6
Sie haben Recht, nur die in definierten Eigenschaften src/test/resources/application.propertieswerden während der Testphase geladen und src/main/resources/application.propertiesignoriert.
Mohnish
11
Wenn Sie bisher keine Profile verwenden, benötigen Sie kein spezielles "Test" -Profil. Nennen Sie einfach Ihre Testeigenschaften application-default.propertiesund sie werden berücksichtigt, da Sie automatisch das "Standard" -Profil ausführen (falls nicht anders angegeben).
FrVaBe
65

Sie können auch Meta-Annotationen verwenden, um die Konfiguration zu externalisieren. Beispielsweise:

@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
quelle
21

Ein weiterer Ansatz, der zum Überschreiben einiger Eigenschaften in Ihrem Test geeignet ist, wenn Sie @SpringBootTestAnmerkungen verwenden:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
quelle
1
nicht SpringBootTestladen Sie die Datei application.properties?
TuGordoBello
8

TLDR:

Also habe ich den Standard src/main/resources/application.propertiesund auch einen, src/test/resources/application-default.propertiesbei dem ich einige Einstellungen für ALLE meine Tests überschreibe.

Ganze Geschichte

Ich bin auf dasselbe Problem gestoßen und habe bisher auch keine Profile verwendet. Es schien lästig zu sein, es jetzt tun zu müssen und sich daran zu erinnern, das Profil deklariert zu haben - was leicht vergessen werden kann.

Der Trick besteht darin, zu nutzen, dass ein Profil bestimmte application-<profile>.propertiesEinstellungen im allgemeinen Profil überschreibt. Siehe https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
quelle
3

Einfache Erklärung:

Wenn Sie wie ich sind und dasselbe application.propertiesin src/main/resourcesund src/test/resourceshaben und sich fragen, warum das application.propertiesin Ihrem Testordner das application.propertiesin Ihren Hauptressourcen nicht überschreibt , lesen Sie weiter ...

Ob Sie application.propertiesunter src/main/resourcesund dasselbe application.propertiesunter haben src/test/resources, was application.propertiesabgeholt wird, hängt davon ab, wie Sie Ihre Tests durchführen . Die Ordnerstruktur src/main/resources und src/test/resourcesist ein Maven architektonische Konvention, also wenn Sie wie Ihr Test ausführen mvnw testoder sogar gradlew test, die application.propertiesin src/test/resourceswird abgeholt, als Test Classpath vorangehen Haupt Classpath. Aber, wenn Sie Ihren Test wie laufen Run as JUnit Testin Elipse / STS, die application.propertiesin src/main/resourceswird abgeholt, als Haupt- Classpath vorangeht Test Classpath.

Sie können es überprüfen, indem Sie das öffnen Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Sie werden so etwas sehen wie:

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

Sehen Sie, dass \ main zuerst kommt und dann \ test ? Richtig, es geht nur um Klassenpfad :-)

Prost

jump_monkey
quelle
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
quelle
1

Wenn Sie Spring 5.2.5 und Spring Boot 2.2.6 verwenden und nur einige Eigenschaften anstelle der gesamten Datei überschreiben möchten. Sie können die neue Anmerkung verwenden: @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
quelle
0

Andernfalls ändern wir möglicherweise den Standardnamen des Eigenschaftenkonfigurators, legen die Eigenschaft fest spring.config.name=testund verfügen dann über eine Klassenpfadressource, deren src/test/test.propertiesnative Instanz org.springframework.boot.SpringApplicationautomatisch aus dieser getrennten test.properties konfiguriert wird, wobei Anwendungseigenschaften ignoriert werden.

Vorteil: automatische Konfiguration von Tests;

Nachteil: Offenlegen der Eigenschaft "spring.config.name" auf der CI-Ebene

Ref: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

spring.config.name = application # Name der Konfigurationsdatei

D. Soloviev
quelle
5
Ignorieren application.propertiesist für mich keine Option, da ich nur einige der ursprünglichen Konfigurationswerte im Test überschreiben möchte .
FrVaBe
Ich habe nach einer Möglichkeit gesucht, einen einzelnen Test durchzuführen, bei dem die Eigenschaften src / main / resources / application.properties nicht geladen werden, und das ist es. Erstellen Sie eine Datei: src / test / resources / empty.properties und fügen Sie die Annotation zu den Tests hinzu, die die Haupteigenschaften ignorieren sollen. @ TestPropertySource (properties = "spring.config.name = empty")
rvertigo
Wie lege ich für jede Junit-Testmethode einen bestimmten Eigenschaftswert fest?
Nicolas
0

Sie können auch eine application.properties-Datei in src / test / resources erstellen, in die Ihre JUnits geschrieben sind.

PragmaticFire
quelle
Wie hilft das? ^^
jump_monkey