Zastąp domyślne ustawienia application.properties Spring-Boot w teście Junit

198

Mam aplikację Spring-Boot, w której właściwości domyślne są ustawione w application.propertiespliku w ścieżce klasy (src / main / resources / application.properties).

Chciałbym zastąpić niektóre ustawienia domyślne w moim teście JUnit właściwościami zadeklarowanymi w test.propertiespliku (src / test / resources / test.properties)

Zwykle mam dedykowaną klasę konfiguracji dla moich testów Junit, np

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 {

}

Najpierw pomyślałem, że użycie @PropertySource("classpath:test.properties")w klasie TestConfig załatwi sprawę, ale te właściwości nie zastąpią ustawień application.properties (patrz Dokumentacja Spring-Boot Reference - 23. Konfiguracja zewnętrzna ).

Następnie próbowałem użyć -Dspring.config.location=classpath:test.propertiespodczas wywoływania testu. To się udało - ale nie chcę ustawiać tej właściwości systemowej dla każdego wykonania testu. Tak więc umieściłem to w kodzie

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

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

}

co niestety znów się nie powiodło.

Musi istnieć proste rozwiązanie, w jaki sposób zastąpić application.propertiesustawienia w testach JUnit, z test.propertiesczym musiałem przeoczyć.

FrVaBe
źródło
Jeśli chcesz skonfigurować tylko kilka właściwości, możesz użyć nowej adnotacji @DynamicPropertySource. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Odpowiedzi:

293

Możesz użyć @TestPropertySourcedo zastąpienia wartości w application.properties. Z javadoc:

źródeł właściwości testowych można użyć do selektywnego przesłonięcia właściwości zdefiniowanych w źródłach właściwości systemu i aplikacji

Na przykład:

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

}
Andy Wilkinson
źródło
2
Otóż ​​to. Dzięki. Niestety nie działa, gdy jest używany w klasie ExampleApplication.class, więc muszę ustawić go dla każdej klasy testowej. Czy to prawda?
FrVaBe
1
Musi on znaleźć się gdzieś w hierarchii klas testowych, tzn. Możesz użyć wspólnej nadklasy, aby skonfigurować ją w wielu różnych klasach testowych.
Andy Wilkinson
64
Pamiętaj też, że @TestPropertySourcemożna zaakceptować propertiesargument zastępujący niektóre właściwości wbudowane, na przykład jest @TestPropertySource(properties = "myConf.myProp=valueInTest")to przydatne w przypadku, gdy nie chcesz całkowicie nowego pliku właściwości.
dyng
2
Możesz określić wiele plików w tablicy, a także pliki w systemie plików (ale pamiętaj, że mogą nie działać na serwerze CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam
8
Zauważ, że @SpringApplicationConfigurationjest to już przestarzałe i powinieneś użyć@SpringBootTest
mrkernelpanic
74

Spring Boot automatycznie ładuje się src/test/resources/application.properties, jeśli zostaną użyte następujące adnotacje

@RunWith(SpringRunner.class)
@SpringBootTest

Zmień nazwę test.propertiesna, application.propertiesaby korzystać z automatycznej konfiguracji.

Jeśli * potrzebujesz * tylko załadować plik właściwości (do środowiska), możesz również skorzystać z następujących elementów, jak wyjaśniono tutaj

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

[ Aktualizacja: przesłanianie niektórych właściwości do testowania ]

  1. Dodaj src/main/resources/application-test.properties.
  2. Opisz klasę testową za pomocą @ActiveProfiles("test").

To ładuje, application.propertiesa następnie application-test.properties właściwości do kontekstu aplikacji dla przypadku testowego, zgodnie z tu zdefiniowanymi regułami .

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

Mohnish
źródło
1
Nie jestem pewien, czy dobrym pomysłem jest posiadanie dwóch application.propertiesplików na ścieżce klasy (jeden do src/main/resourcesi jeden do src/test/resources). Kto gwarantuje, że oba zostaną wzięte, a który zostanie wzięty jako pierwszy?
FrVaBe,
3
@FrVaBe Spring to zagwarantuje! Główne właściwości profilu są zawsze ładowane. Następnie podczas fazy testowej ładowane są właściwości testowe, dodając / zastępując nowe / istniejące właściwości. Jeśli nie podoba utrzymywanie dwóch plików o tej samej nazwie, a następnie można dodać application-test.propertiesw src/main/resourcesi określić testjako aktywnego profilu w przypadku testu.
Mohnish
7
Wiosna nie daje gwarancji. Narzędzie do budowania użyje zasobów testowych na rzecz głównych zasobów podczas testów. Ale w przypadku testu application.properties główne application.properties zostaną zignorowane. Nie tego chcę, ponieważ główna zawiera kilka użytecznych wartości domyślnych i muszę tylko przesłonić niektóre z nich podczas testu (i nie chcę duplikować całego pliku w sekcji testowej). Zobacz tutaj .
FrVaBe
6
Masz rację, tylko właściwości zdefiniowane w src/test/resources/application.propertiessą ładowane podczas fazy testowej, src/main/resources/application.propertiessą ignorowane.
Mohnish
11
Jeśli do tej pory nie korzystasz z profili, nie potrzebujesz dedykowanego profilu „testowego”. Po prostu nazwij swoje właściwości testowe, application-default.propertiesa zostaną one uwzględnione, ponieważ automatycznie uruchamiasz profil „domyślny” (jeśli nie został zadeklarowany).
FrVaBe
65

Możesz także użyć meta-adnotacji do uzewnętrznienia konfiguracji. Na przykład:

@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
źródło
21

Inne podejście odpowiednie do zastąpienia kilku właściwości w teście, jeśli używasz @SpringBootTestadnotacji:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
źródło
1
ma SpringBootTestzaładować plik application.properties?
TuGordoBello,
8

TLDR:

Więc to, co zrobiłem, to mieć standard, src/main/resources/application.propertiesa także miejsce, w src/test/resources/application-default.propertiesktórym zastępuję niektóre ustawienia WSZYSTKICH moich testów.

Cała historia

Natknąłem się na ten sam problem i do tej pory nie korzystałem z profili. Wydawało się, że kłopotliwe jest robić to teraz i pamiętać o ogłoszeniu profilu - o którym łatwo zapomnieć.

Sztuka polega na tym, aby wykorzystać to, że określony profil application-<profile>.propertieszastępuje ustawienia w profilu ogólnym. Zobacz https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
źródło
3

Proste wyjaśnienie:

Jeśli jesteś podobny do mnie i masz to samo application.propertiesw src/main/resourcesi src/test/resources, a ty zastanawiasz się , dlaczego application.propertiesw folderze testowym nie jest nadrzędneapplication.properties w głównych zasobów, czytaj dalej ...

Jeśli masz application.propertiesunder src/main/resourcesi to samo application.propertiesunder src/test/resources, które application.propertieszostanie podniesione, zależy od tego, jak przeprowadzasz testy . Folder struktura src/main/resources i src/test/resources, to Maven konwencja architektoniczny, więc jeśli uruchomić test podobny mvnw testlub nawet gradlew test, application.propertiesw src/test/resourceszostanie wybrana, jako próba classpath poprzedzi główną ścieżkę klasy. Ale jeśli uruchomisz test tak jak Run as JUnit Testw Elipse / STS, application.propertiesin src/main/resourceszostanie odebrane, ponieważ główna ścieżka klasy poprzedza ścieżkę klasy testu .

Możesz to sprawdzić, otwierając Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Zobaczysz coś takiego:

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

Czy widzisz, że \ main jest pierwszy, a potem \ test ? Racja, chodzi o ścieżkę klas :-)

Twoje zdrowie

jumping_monkey
źródło
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
źródło
1

Jeśli używasz Spring 5.2.5 i Spring Boot 2.2.6 i chcesz zastąpić tylko kilka właściwości zamiast całego pliku. Możesz użyć nowej adnotacji: @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
źródło
0

W przeciwnym razie możemy zmienić domyślną nazwę konfiguratora właściwości, ustawiając właściwość, spring.config.name=testa następnie mając zasób klasy, src/test/test.propertiesnasza natywna instancja org.springframework.boot.SpringApplicationzostanie automatycznie skonfigurowana z tego oddzielnego pliku test.properties, ignorując właściwości aplikacji;

Korzyści: automatyczna konfiguracja testów;

Wada: ujawnienie właściwości „spring.config.name” na warstwie CI

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

spring.config.name = application # Config file name

D. Sołowiew
źródło
5
Ignorowanie application.propertiesnie jest dla mnie opcją, ponieważ chcę zastąpić tylko niektóre oryginalne wartości konfiguracji w teście.
FrVaBe,
Szukałem sposobu na pojedynczy test, który nie ładuje pliku src / main / resources / application.properties i to jest to. Utwórz plik: src / test / resources / empty.properties i dodaj adnotację do testów, które powinny zignorować główne właściwości. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo
Jak ustawić określoną wartość właściwości dla każdej metody testowania Junit?
Nicolas
0

Możesz także utworzyć plik application.properties w src / test / resources, w którym zapisane są JUnits.

PragmaticFire
źródło
Jak to pomaga? ^^
jumping_monkey