Sostituisci le impostazioni application.properties di Spring-Boot predefinite in Junit Test


198

Ho un'applicazione Spring-Boot in cui le proprietà predefinite sono impostate in un application.propertiesfile nel percorso di classe (src / main / resources / application.properties).

Vorrei sovrascrivere alcune impostazioni predefinite nel mio test JUnit con le proprietà dichiarate in un test.propertiesfile (src / test / resources / test.properties)

Di solito ho una lezione di configurazione dedicata per i miei test Junit, ad es

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 {

}

Ho pensato che usare @PropertySource("classpath:test.properties")la classe TestConfig avrebbe funzionato, ma queste proprietà non sovrascrivevano le impostazioni application.properties (vedi Documento di riferimento di Spring-Boot - 23. Configurazione esterna ).

Quindi ho provato a usare -Dspring.config.location=classpath:test.propertiesquando invoco il test. Ciò ha avuto esito positivo, ma non voglio impostare questa proprietà di sistema per ogni esecuzione del test. Quindi l'ho inserito nel codice

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

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

}

che sfortunatamente non ebbe ancora successo.

Ci deve essere una soluzione semplice su come sovrascrivere le application.propertiesimpostazioni nei test JUnit con test.propertiesquella che devo aver trascurato.


Se è necessario configurare solo alcune proprietà, è possibile utilizzare la nuova annotazione @DynamicPropertySource. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Risposte:


293

È possibile utilizzare @TestPropertySourceper sovrascrivere i valori in application.properties. Dal suo javadoc:

le origini delle proprietà del test possono essere utilizzate per sovrascrivere selettivamente le proprietà definite nelle origini delle proprietà del sistema e dell'applicazione

Per esempio:

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

}

2
Questo è tutto. Grazie. Sfortunatamente, non funziona se utilizzato su ExampleApplication.class, quindi devo impostarlo su ogni classe di test. È giusto?
FrVaBe,

1
Deve andare da qualche parte nella gerarchia della classe di test, vale a dire che potresti usare una superclasse comune per configurarla attraverso un numero di diverse classi di test.
Andy Wilkinson,

64
Si noti inoltre che @TestPropertySourcepuò accettare un propertiesargomento per sovrascrivere alcune proprietà in linea, ad esempio @TestPropertySource(properties = "myConf.myProp=valueInTest"), è utile nel caso in cui non si desideri un file di proprietà completamente nuovo di zecca.
dyng,

2
Puoi specificare più file in un array e anche file nel file system (ma ricorda che potrebbero non funzionare sul server CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam

8
Nota che @SpringApplicationConfigurationè già obsoleto e dovresti usare@SpringBootTest
mrkernelpanic il

74

Spring Boot si carica automaticamente src/test/resources/application.properties, se vengono utilizzate le seguenti annotazioni

@RunWith(SpringRunner.class)
@SpringBootTest

Quindi, rinominare test.propertiesin application.propertiesper utilizzare la configurazione automatica.

Se * solo * devi caricare il file delle proprietà (nell'ambiente) puoi anche usare quanto segue, come spiegato qui

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

[ Aggiornamento: sovrascrivere alcune proprietà per il test ]

  1. Aggiungi src/main/resources/application-test.properties.
  2. Annota la classe di test con @ActiveProfiles("test").

Questo carica application.propertiese quindi le application-test.properties proprietà nel contesto dell'applicazione per il test case, come da regole qui definite .

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


1
Non sono sicuro che sia una buona idea avere due application.propertiesfile sul percorso di classe (uno in src/main/resourcese uno in src/test/resources). Chi garantisce che entrambi saranno presi e quale sarà preso per primo?
FrVaBe,

3
@FrVaBe Spring lo garantirà! Le proprietà del profilo principale vengono sempre caricate. Quindi durante la fase di test vengono caricate le proprietà del test, aggiungendo / sovrascrivendo proprietà nuove / esistenti. Se non lo fai come tenere due file con lo stesso nome, quindi è possibile aggiungere application-test.propertiesin src/main/resourcese specificare testcome il profilo attivo nel caso di test.
Mohnish,

7
La primavera non offre una garanzia. Lo strumento di compilazione utilizzerà le risorse di test a favore delle risorse principali durante i test. Ma nel caso di un test application.properties, il principale application.properties verrà ignorato. Non è quello che voglio perché quello principale contiene diversi utili valori predefiniti e ho solo bisogno di sovrascriverne alcuni durante il test (e non voglio duplicare l'intero file nella sezione test). Vedi qui .
FrVaBe,

6
Hai ragione, src/test/resources/application.propertiesdurante la fase di test vengono caricate solo le proprietà definite in , src/main/resources/application.propertiesvengono ignorate.
Mohnish,

11
Se finora non si utilizzano profili, non è necessario un profilo "test" dedicato. Basta nominare le proprietà del test application-default.propertiese verranno prese in considerazione perché si esegue automaticamente il profilo "predefinito" (se non dichiarato altro).
FrVaBe,

65

È inoltre possibile utilizzare meta-annotazioni per esternalizzare la configurazione. Per esempio:

@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 { }

21

Un altro approccio adatto per sovrascrivere alcune proprietà nel test, se si utilizza l' @SpringBootTestannotazione:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})

1
non SpringBootTestcaricare il file application.properties?
TuGordoBello,

8

TLDR:

Quindi quello che ho fatto è stato avere lo standard src/main/resources/application.propertiese anche un punto in src/test/resources/application-default.propertiescui ho ignorato alcune impostazioni per TUTTI i miei test.

L'intera storia

Ho riscontrato lo stesso problema e finora non utilizzavo i profili. Sembrava fastidioso doverlo fare ora e ricordare di aver dichiarato il profilo - che può essere facilmente dimenticato.

Il trucco è, per sfruttare il fatto che un profilo specifico ha la precedenza sulle application-<profile>.propertiesimpostazioni nel profilo generale. Vedi https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .


3

Spiegazione semplice:

Se siete come me e si ha la stessa application.propertiesin src/main/resourcese src/test/resources, e si sta chiedendo il motivo per cui l' application.propertiesnella cartella test non è prioritarie nella application.propertiesnelle vostre risorse principali, continua a leggere ...

Se hai application.propertiessotto src/main/resourcese lo stesso application.propertiessotto src/test/resources, che application.propertiesviene raccolto, dipende da come stai eseguendo i test . La struttura delle cartelle src/main/resourcese src/test/resources, è una convenzione architettonica di Maven, quindi se si esegue il test in modo uguale mvnw testo uniforme gradlew test, application.propertiesin src/test/resourcesverrà acquisito, poiché il percorso di classe test precederà il percorso di classe principale . Ma, se esegui il tuo test come Run as JUnit Testin Elipse / STS, application.propertiesin src/main/resourcesverrà prelevato come principale percorso di classe precede il percorso di classe test .

Puoi verificarlo aprendo il Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Vedrai qualcosa come:

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-primavera-tool-suite 4-4.5.1.RELEASE \ project_name \ bin \ test;

Vedi che \ main viene prima e poi \ test ? Bene, si tratta di un percorso di classe :-)

Saluti


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`

1

Se si utilizza Spring 5.2.5 e Spring Boot 2.2.6 e si desidera sovrascrivere solo alcune proprietà anziché l'intero file. È possibile utilizzare la nuova annotazione: @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);
    }
}

0

Altrimenti potremmo cambiare il nome del configuratore di proprietà predefinito, impostando la proprietà spring.config.name=teste quindi avendo la risorsa del percorso di classe la src/test/test.propertiesnostra istanza nativa org.springframework.boot.SpringApplicationverrà configurata automaticamente da questo test.properties separato, ignorando le proprietà dell'applicazione;

Vantaggio: autoconfigurazione dei test;

Svantaggio: esporre la proprietà "spring.config.name" al livello CI

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

spring.config.name = application # Nome file di configurazione


5
Ignorare application.propertiesnon è un'opzione per me poiché voglio solo sostituire alcuni dei valori di configurazione originali nel test.
FrVaBe,

Ho cercato un modo per avere un singolo test che non carica src / main / resources / application.properties e questo è tutto. Creare un file: src / test / resources / empty.properties e aggiungere l'annotazione ai test che dovrebbero ignorare le proprietà principali. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo

Come impostare un valore di proprietà specifico per ciascun metodo di test junit?
Nicolas

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.