Переопределить стандартные настройки Spring.boot application.properties в тесте Junit

198

У меня есть приложение Spring-Boot, где свойства по умолчанию установлены в application.propertiesфайле в classpath (src / main / resources / application.properties).

Я хотел бы переопределить некоторые настройки по умолчанию в моем тесте JUnit свойствами, объявленными в test.propertiesфайле (src / test / resources / test.properties)

У меня обычно есть специальный класс Config для моих тестов Junit, например

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 {

}

Сначала я подумал, что использование @PropertySource("classpath:test.properties")в классе TestConfig поможет, но эти свойства не будут перезаписывать настройки application.properties (см. Справочный документ Spring-Boot - 23. Внешняя конфигурация ).

Затем я попытался использовать -Dspring.config.location=classpath:test.propertiesпри вызове теста. Это было успешно - но я не хочу устанавливать это системное свойство для каждого выполнения теста. Таким образом я положил это в коде

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

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

}

что, к сожалению, снова не удалось.

Должно быть простое решение о том, как переопределить application.propertiesнастройки в тестах JUnit, test.propertiesкоторые я должен был пропустить.

FrVaBe
источник
Если вам нужно настроить всего несколько свойств, вы можете использовать новую аннотацию @DynamicPropertySource. stackoverflow.com/a/60941845/8650621
Фелипе Дезидерати

Ответы:

293

Вы можете использовать @TestPropertySourceдля переопределения значений в application.properties. Из своего javadoc:

источники свойств теста могут использоваться для выборочного переопределения свойств, определенных в источниках свойств системы и приложения

Например:

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

}
Энди Уилкинсон
источник
2
Вот и все. Спасибо. К сожалению, он не работает при использовании в классе ExampleApplication.class, поэтому я должен установить его для каждого класса тестирования. Это правильно?
FrVaBe
1
Он должен идти где-то в иерархии тестового класса, т. Е. Вы можете использовать общий суперкласс для настройки его в нескольких различных тестовых классах.
Энди Уилкинсон
64
Также обратите внимание, что @TestPropertySourceможет принимать propertiesаргумент для перезаписи некоторого встроенного свойства, например @TestPropertySource(properties = "myConf.myProp=valueInTest"), это полезно, если вам не нужен совершенно новый файл свойств.
dyng
2
Вы можете указать несколько файлов в массиве, а также файлы в файловой системе (но помните, что они могут не работать на сервере CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Адам
8
Обратите внимание, что @SpringApplicationConfigurationэто уже устарело, и вы должны использовать@SpringBootTest
mrkernelpanic
74

Spring Boot автоматически загружается src/test/resources/application.properties, если используются следующие аннотации

@RunWith(SpringRunner.class)
@SpringBootTest

Таким образом, переименование test.propertiesдо application.propertiesиспользовать автоматическую конфигурацию.

Если вам * нужно * загрузить файл свойств (в среду), вы также можете использовать следующее, как описано здесь

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

[ Обновление: переопределение определенных свойств для тестирования ]

  1. Добавить src/main/resources/application-test.properties.
  2. Аннотировать тестовый класс с @ActiveProfiles("test").

Это загружает application.propertiesи затем application-test.properties свойства в контекст приложения для контрольного примера, согласно правилам, определенным здесь .

Демонстрация - https://github.com/mohnish82/so-spring-boot-testprops

Mohnish
источник
1
Не уверен, будет ли хорошей идеей иметь два application.propertiesфайла в пути к классам (один вход src/main/resourcesи один вход src/test/resources). Кто гарантирует, что оба будут взяты, и какой будет взят первым?
FrVaBe
3
@FrVaBe Spring это гарантирует! Основные свойства профиля всегда загружены. Затем на этапе тестирования загружаются свойства теста, добавляются / переопределяются новые / существующие свойства. Если вам не нравится держать два файла с одинаковым именем, то вы можете добавить application-test.propertiesв src/main/resourcesи указать в testкачестве активного профиля в тесте.
Могниш
7
Весна не дает гарантии. Инструмент сборки будет использовать тестовые ресурсы в пользу основных ресурсов во время тестов. Но в случае тестового application.properties основные application.properties будут игнорироваться. Это не то, что я хочу, потому что главное содержит несколько полезных значений по умолчанию, и мне нужно только переопределить некоторые из них во время теста (и я не хочу дублировать весь файл в разделе теста). Смотрите здесь .
FrVaBe
6
Вы правы, только свойства, определенные в src/test/resources/application.propertiesзагружаются во время фазы тестирования, src/main/resources/application.propertiesигнорируется.
Могниш
11
Если вы до сих пор не используете профили, вам не нужен специальный «тестовый» профиль. Просто назовите свои тестовые свойства, application-default.propertiesи они будут учтены, потому что вы автоматически запускаете профиль «по умолчанию» (если не объявлен другой).
FrVaBe
65

Вы также можете использовать метааннотации для вывода конфигурации. Например:

@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

Другой подход, подходящий для переопределения нескольких свойств в вашем тесте, если вы используете @SpringBootTestаннотацию:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
источник
1
это SpringBootTestзагрузить файл application.properties?
TuGordoBello
8

TLDR:

Так что я сделал, чтобы был стандарт, src/main/resources/application.propertiesа также src/test/resources/application-default.propertiesгде я переопределил некоторые настройки для всех моих тестов.

Вся история

Я столкнулся с той же проблемой и до сих пор не использовал профили. Казалось, надоело делать это сейчас и помнить объявление профиля - который можно легко забыть.

Хитрость заключается в том, чтобы использовать, что определенный профиль application-<profile>.propertiesпереопределяет настройки в общем профиле. См. Https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
источник
3

Простое объяснение:

Если вы похожи на меня , и у вас есть то же самое application.propertiesв src/main/resourcesи src/test/resources, и вы интересно , почему application.propertiesв вашей папке тестов не перекрываяapplication.properties в основных ресурсах, читайте дальше ...

Если у вас есть application.propertiesпод src/main/resourcesи то же самое application.propertiesпод src/test/resources, которое application.propertiesподбирается, зависит от того, как вы выполняете свои тесты . Папка структура src/main/resources и src/test/resourcesявляется Maven архитектурного соглашением, так что если вы запускаете тест , как mvnw testили даже gradlew test, то application.propertiesв src/test/resourcesбудет получить взяли, так как тест путь к классам будут предшествовать основной путь к классам. Но, если вы запускаете тест , как Run as JUnit Testв ELIPSE / STS, то application.propertiesв src/main/resourcesбудет получить взял, как и основные пути к классам предшествуют тест классы.

Вы можете проверить это, открыв Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Вы увидите что-то вроде:

XXXbin \ javaw.exe -ea -Dfile.encoding = UTF-8 -classpath XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ main; XXX \ рабочее пространство-весна-инструмент-люкс-4-4.5.1.RELEASE \ project_name \ Bin \ тест;

Вы видите, что сначала идет \ main , а затем \ test ? Да, это все о classpath :-)

ура

jumping_monkey
источник
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

Если вы используете Spring 5.2.5 и Spring Boot 2.2.6 и хотите переопределить только несколько свойств вместо всего файла. Вы можете использовать новую аннотацию: @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

В противном случае мы можем изменить имя конфигуратора свойств по умолчанию, задав свойство spring.config.name=testи затем имея ресурс пути к классу, src/test/test.propertiesнаш собственный экземпляр которого org.springframework.boot.SpringApplicationбудет автоматически конфигурироваться из этого разделенного test.properties, игнорируя свойства приложения;

Преимущество: автоконфигурация тестов;

Недостаток: экспонирование свойства "spring.config.name" на уровне CI

ссылка: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

spring.config.name = application # Имя файла конфигурации

Д. Соловьев
источник
5
Игнорирование application.properties- не вариант для меня, поскольку я хочу переопределить только некоторые исходные значения конфигурации в тесте.
FrVaBe
Я искал способ иметь единственный тест, который не загружал бы src / main / resources / application.properties, и это все. Создайте файл: src / test / resources / empty.properties и добавьте аннотацию к тесту (-ам), которая должна игнорировать основные свойства. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo
Как установить конкретное значение свойства для каждого метода тестирования junit?
Николас
0

Вы также можете создать файл application.properties в src / test / resources, где написаны ваши JUnits.

PragmaticFire
источник
Как это помогает? ^^
jumping_monkey