[英]Override default Spring-Boot application.properties settings in Junit Test
I have a Spring-Boot application where the default properties are set in an application.properties
file in the classpath (src/main/resources/application.properties).我有一个 Spring-Boot 应用程序,其中默认属性设置在类路径 (src/main/resources/application.properties) 的application.properties
文件中。
I would like to override some default settings in my JUnit test with properties declared in a test.properties
file (src/test/resources/test.properties)我想用test.properties
文件 (src/test/resources/test.properties) 中声明的属性覆盖我的 JUnit 测试中的一些默认设置
I usualy have a dedicated Config Class for my Junit Tests, eg我通常有一个专用的配置 Class 用于我的 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 {
}
I first thought that using @PropertySource("classpath:test.properties")
in the TestConfig class would do the trick, but these properties will not overwrite the application.properties settings (see Spring-Boot Reference Doc - 23. Externalized Configuration ).我首先想到在 TestConfig class 中使用@PropertySource("classpath:test.properties")
可以解决问题,但这些属性不会覆盖 application.properties 设置(请参阅 Spring-Boot 参考文档 - 23. 外部化配置)。
Then I tried to use -Dspring.config.location=classpath:test.properties
when invoking the test.然后我尝试在调用测试时使用-Dspring.config.location=classpath:test.properties
。 That was successful - but I don't want to set this system property for each test execution.那是成功的——但我不想为每个测试执行设置这个系统属性。 Thus I put it in the code因此我把它放在代码中
@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {
static {
System.setProperty("spring.config.location", "classpath:test.properties");
}
}
which unfortunatly was again not successful.不幸的是,这再次没有成功。
There must be a simple solution on how to override application.properties
settings in JUnit tests with test.properties
that I must have overlooked.必须有一个简单的解决方案,说明如何使用 test.properties 覆盖test.properties
测试中的application.properties
设置,我一定忽略了这一点。
You can use @TestPropertySource
to override values in application.properties
.您可以使用@TestPropertySource
来覆盖application.properties
值。 From its javadoc:从它的javadoc:
test property sources can be used to selectively override properties defined in system and application property sources测试属性源可用于选择性地覆盖系统和应用程序属性源中定义的属性
For example:例如:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {
}
Spring Boot automatically loads src/test/resources/application.properties
, if following annotations are used Spring Boot 会自动加载src/test/resources/application.properties
,如果使用以下注解
@RunWith(SpringRunner.class)
@SpringBootTest
So, rename test.properties
to application.properties
to utilize auto configuration.因此,将test.properties
重命名为application.properties
以利用自动配置。
If you only need to load the properties file (into the Environment) you can also use the following, as explained here如果你只需要加载的属性文件(进入环境),您也可以使用下面的,因为解释这里
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
[ Update: Overriding certain properties for testing ] [更新:覆盖某些属性进行测试]
src/main/resources/application-test.properties
.添加src/main/resources/application-test.properties
。@ActiveProfiles("test")
.使用@ActiveProfiles("test")
注释测试类。 This loads application.properties
and then application-test.properties
properties into application context for the test case, as per rules defined here .此负载application.properties
然后application-test.properties
属性到用于测试案例应用背景下,作为每规则定义这里。
Demo - https://github.com/mohnish82/so-spring-boot-testprops演示 - https://github.com/mohnish82/so-spring-boot-testprops
You can also use meta-annotations to externalize the configuration.您还可以使用元注释来外部化配置。 For example:例如:
@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 { }
如果您使用@SpringBootTest
注释,则另一种适合覆盖测试中的一些属性的方法:
@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
So what I did was to have the standard src/main/resources/application.properties
and also a src/test/resources/application-default.properties
where i override some settings for ALL my tests.所以我所做的是拥有标准的src/main/resources/application.properties
和一个src/test/resources/application-default.properties
在这里我覆盖了我所有测试的一些设置。
In order to change/use even more easily different spring profiles, I have a now an application-default.yaml
that declares the profiles I want to use.为了更轻松地更改/使用不同的 spring 配置文件,我现在有一个application-default.yaml
来声明我想要使用的配置文件。 This file is not committed, so that each developer may choose his way of activating profiles and needs (eg feature) he/she is working on.此文件未提交,因此每个开发人员可以选择他/她正在处理的配置文件和需求(例如功能)的激活方式。
spring:
profiles:
include:
- local
- devlocal
- wip
# - kafka@docker
---
spring.profiles: wip
# ... overriding properties
I ran into the same problem and was not using profiles either so far.我遇到了同样的问题,到目前为止也没有使用配置文件。 It seemed to be bothersome to have to do it now and remember declaring the profile -- which can be easily forgotten.现在必须这样做并记住声明配置文件似乎很麻烦——这很容易被忘记。
The trick is, to leverage that a profile specific application-<profile>.properties
overrides settings in the general profile.诀窍是,利用特定于配置文件的application-<profile>.properties
覆盖通用配置文件中的设置。 See https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .请参阅https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties 。
If you are like me and you have the same application.properties
in src/main/resources
and src/test/resources
, and you are wondering why the application.properties
in your test folder is not overriding the application.properties
in your main resources, read on...如果你像我和你有相同的application.properties
中src/main/resources
和src/test/resources
,和你想知道为什么application.properties
在测试文件夹不重写application.properties
在主资源,继续阅读……
If you have application.properties
under src/main/resources
and the same application.properties
under src/test/resources
, which application.properties
gets picked up, depends on how you are running your tests .如果您在src/main/resources
下有application.properties
并且在src/test/resources
下有相同的application.properties
,那么application.properties
会被选取,这取决于您如何运行测试。 The folder structure src/main/resources
and src/test/resources
, is a Maven architectural convention, so if you run your test like mvnw test
or even gradlew test
, the application.properties
in src/test/resources
will get picked up, as test classpath will precede main classpath.文件夹结构src/main/resources
和src/test/resources
是 Maven 架构约定,因此如果您像mvnw test
甚至gradlew test
一样运行gradlew test
, src/test/resources
的application.properties
将被选中,因为测试类路径将在主类路径之前。 But, if you run your test like Run as JUnit Test
in Eclipse/STS, the application.properties
in src/main/resources
will get picked up, as main classpath precedes test classpath.但是,如果您像Run as JUnit Test
in Eclipse/STS 一样Run as JUnit Test
,则src/main/resources
的application.properties
将被选中,因为主类路径在测试类路径之前。
You can check it out by opening the menu bar Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line"
.您可以通过打开菜单栏Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line"
。
You will see something like this:你会看到这样的事情:
XXXbin\\javaw.exe -ea -Dfile.encoding=UTF-8 -classpath 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\\main;
XXX\\workspace-spring-tool-suite-4-4.5.1.RELEASE\\project_name\\bin\\test; XXX\\workspace-spring-tool-suite-4-4.5.1.RELEASE\\project_name\\bin\\test;
Do you see that classpath xxx\\main comes first, and then xxx\\test ?您是否看到classpath xxx\\main首先出现,然后是xxx\\test ? Right, it's all about classpath :-)是的,这都是关于类路径的:-)
Side-note: Be mindful that properties overridden in the Launch Configuration(In Spring Tool Suite IDE, for example) takes priority over application.properties.旁注:请注意,在启动配置中覆盖的属性(例如在 Spring Tool Suite IDE 中)优先于 application.properties。
Now, everything is configurable in Spring.现在,一切都可以在 Spring 中进行配置。 You can change the build classpath, so that xxx\\test comes first, and then xxx\\main .您可以更改构建类路径,以便xxx\\test首先出现,然后是xxx\\main 。
Simply go to Project > Properties > Java Build Path > Order and Export
, change the build class path order by putting any of the test folder first such as:只需转到Project > Properties > Java Build Path > Order and Export
,通过将任何测试文件夹放在第一位来更改构建类路径顺序,例如:
And that's it!就是这样!
A better solution though, when testing, would be to activate the src/test/resources/application-{profile}.properties
(where profile
can be test), such as the following in src/main/resources/application.properties
:但是,在测试时,更好的解决方案是激活src/test/resources/application-{profile}.properties
(可以测试profile
),例如src/main/resources/application.properties
:
spring.profiles.active=test spring.profiles.active=测试
This is neater, and gives you complete control on what profile to activate when doing what.这更简洁,让您可以完全控制在做什么时要激活的配置文件。
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`
If you're using Spring 5.2.5 and Spring Boot 2.2.6 and want to override just a few properties instead of the whole file.如果您使用的是 Spring 5.2.5 和 Spring Boot 2.2.6,并且只想覆盖几个属性而不是整个文件。 You can use the new annotation: @DynamicPropertySource您可以使用新注释:@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);
}
}
Otherwise we may change the default property configurator name, setting the property spring.config.name=test
and then having class-path resource src/test/test.properties
our native instance of org.springframework.boot.SpringApplication
will be auto-configured from this separated test.properties, ignoring application properties;否则我们可能会更改默认的属性配置器名称,设置属性spring.config.name=test
然后让类路径资源src/test/test.properties
我们的org.springframework.boot.SpringApplication
本机实例将被自动配置从这个分离的 test.properties 中,忽略应用程序属性;
Benefit: auto-configuration of tests;优点:自动配置测试;
Drawback: exposing "spring.config.name" property at CI layer缺点:在 CI 层暴露“spring.config.name”属性
ref: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html参考: http : //docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.config.name=application # Config file name spring.config.name=application # 配置文件名
您还可以在编写 JUnit 的 src/test/resources 中创建 application.properties 文件。
I think you can also use this:我想你也可以使用这个:
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
when custom config locations are configured by using spring.config.additional-location, they are used in addition to the default locations.当使用 spring.config.additional-location 配置自定义配置位置时,除了默认位置之外,还会使用它们。
The file will have precedence该文件将具有优先权
You can create a spring.factories file in src/test/resources/META-INF and a EnvironmentPostProcessor Implementation class in src/test/java.您可以在 src/test/resources/META-INF 中创建一个 spring.factories 文件,并在 src/test/java 中创建一个 EnvironmentPostProcessor 实现类。
spring.factories
like spring.factories
喜欢
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.test.YourTestPropertiesConfig
YourTestPropertiesConfig.java
like YourTestPropertiesConfig.java
喜欢
package com.example.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class YourTestPropertiesConfig implements EnvironmentPostProcessor {
private static final Map<String, Object> testProperties = new HashMap<>();
private static final Set<String> testPropertiesFile = new HashSet<>();
static {
//Add the properties you need to take effect globally in the test directly here.
testProperties.put("spring.jackson.time-zone", "GMT");
testPropertiesFile.add("classpath:test.properties");
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
environment.getPropertySources().addFirst(new MapPropertySource("TestProperties", testProperties));
for (String location : testPropertiesFile) {
try {
environment.getPropertySources().addFirst(new ResourcePropertySource(location));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void addProperty(String key, Object value) {
testProperties.put(key, value);
}
public static void addProperty(String location) {
testPropertiesFile.add(location);
}
}
This workes for me:这对我有用:
My Test:我的测试:
@SpringBootTest
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
class EngineApplicationTests {
@Test
void contextLoads() {
}
}
My versions:我的版本:
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
}
group = 'com.kubemachine'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2021.0.3")
}
The only test dependency in my gradle file:我的 gradle 文件中唯一的测试依赖项:
testImplementation 'org.springframework.boot:spring-boot-starter-test'
I also have this in my build.gradle file:我的 build.gradle 文件中也有这个:
test {
useJUnitPlatform()
}
and two properties file:和两个属性文件:
And in this setup application-test.yml definitely ONLY overrides the values in application.yml.在这个设置中,application-test.yml 绝对只会覆盖 application.yml 中的值。 I don't have to repeat the property values from application.yml in application-test.yml.我不必在 application-test.yml 中重复 application.yml 中的属性值。 application-test.yml really extends application.yml. application-test.yml 确实扩展了 application.yml。
Using使用
.yaml
file-ending用.yaml
文件结尾声明的属性I noticed that the precedence of @TestPropertySource(locations)
was not applied as it would be with .properties
files.我注意到@TestPropertySource(locations)
的优先级没有像.properties
文件那样应用。
The problem I was having was, that Spring kept loading all .yaml
properties (especially those from production) and overriding the properties meant for the tests with the values specified for prod.我遇到的问题是,Spring 一直在加载所有.yaml
属性(尤其是生产中的属性),并使用为产品指定的值覆盖用于测试的属性。 ( sigh ) (叹气)
We come up with the workaround of overwriting the config-scraping mechanism by specifying just my application-test.yaml
as the only properties used like so:我们提出了通过仅指定我的application-test.yaml
作为唯一使用的属性来覆盖配置抓取机制的解决方法,如下所示:
@TestPropertySource(properties = "spring.config.location=classpath:/application-test.yaml")
If you really want/have to use System.setProperties(...)
then use a Junit extension and annotate the test class:如果你真的想/必须使用System.setProperties(...)
然后使用 Junit 扩展并注释测试 class:
...
@ExtendWith(MyBeforeAllCallback.class)
public SomeTestClass ...
and use the constructor of the callback to set the system properties.并使用回调的构造函数来设置系统属性。
public MyBeforeAllCallback implements BeforeAllCallback {
public MyBeforeAllCallback() {
// wicket 9 workaround for java 17 / cglib issue.
System.setProperty("wicket.ioc.useByteBuddy", "true");
// ... whatever you want ...
System.setProperty("whatever", "you need it badly");
}
void beforeAll(ExtensionContext context) {
// ... empty
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.