在 Junit 测试中覆盖默认 Spring-Boot application.properties 设置
Override default Spring-Boot application.properties settings in Junit Test
我有一个 Spring-Boot 应用程序,其中默认属性设置在 class 路径 (src/main/resources/application.properties) 的 application.properties
文件中。
我想用 test.properties
文件中声明的属性覆盖我的 JUnit 测试中的一些默认设置 (src/test/resources/test.properties)
我通常有一个专门的配置 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 {
}
我最初认为在 TestConfig class 中使用 @PropertySource("classpath:test.properties")
可以解决问题,但这些属性不会覆盖 application.properties 设置(参见 Spring-Boot参考文档 - 23. Externalized Configuration).
然后我尝试在调用测试时使用-Dspring.config.location=classpath:test.properties
。那是成功的 - 但我不想为每个测试执行设置此系统 属性。因此我把它放在代码中
@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {
static {
System.setProperty("spring.config.location", "classpath:test.properties");
}
}
不幸的是,这又一次没有成功。
关于如何使用 test.properties
覆盖 JUnit 测试中的 application.properties
设置,一定有一个简单的解决方案,我一定是忽略了。
您可以使用 @TestPropertySource
覆盖 application.properties
中的值。从它的 javadoc:
test property sources can be used to selectively override properties defined in system and application property sources
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {
}
您还可以使用 meta-annotations 来外部化配置。例如:
@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 { }
否则我们可能会更改默认的 属性 配置器名称,设置 属性 spring.config.name=test
然后拥有 class-path 资源
src/test/test.properties
我们 org.springframework.boot.SpringApplication
的本机实例将从这个分离的 test.properties 中自动配置,忽略应用程序属性;
好处:自动配置测试;
缺点:在 C.I 处暴露 "spring.config.name" 属性。图层
参考:http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.config.name=application # Config file name
Spring 引导自动加载 src/test/resources/application.properties
,如果使用以下注释
@RunWith(SpringRunner.class)
@SpringBootTest
因此,将 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)
[更新:重写某些属性以进行测试]
- 添加
src/main/resources/application-test.properties
.
- 用
@ActiveProfiles("test")
注释测试class。
这会将 application.properties
和 然后 application-test.properties
属性加载到测试用例的应用程序上下文中,按照定义的规则 here。
TLDR:
所以我所做的是拥有标准 src/main/resources/application.properties
和 src/test/resources/application-default.properties
,我在其中覆盖了所有测试的一些设置。
对于电源开发人员:
为了 change/use 更容易地改变 spring 配置文件,我现在有一个 application-default.yaml
来声明我想使用的配置文件。
此文件未提交,因此每个开发人员都可以选择激活配置文件和需求(例如功能)的方式 he/she 正在处理。
spring:
profiles:
include:
- local
- devlocal
- wip
# - kafka@docker
---
spring.profiles: wip
# ... overriding 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。
您还可以在编写 JUnit 的 src/test/resources 中创建一个 application.properties 文件。
另一种适用于覆盖测试中的一些属性的方法,如果您使用 @SpringBootTest
注释:
@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
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`
如果您像我一样,在 src/main/resources
和 src/test/resources
中有相同的 application.properties
,并且您想知道 为什么 application.properties
在你的测试文件夹中 没有覆盖 在你的主要资源中的 application.properties
,继续阅读...
简单说明:
如果您在 src/main/resources
下有 application.properties
并且在 src/test/resources
下有相同的 application.properties
,application.properties
被拾取, 取决于关于您如何 运行 测试 。文件夹 structure src/main/resources
和 src/test/resources
是 Maven 架构约定,所以如果你 运行 你的测试像 mvnw test
甚至 gradlew test
,src/test/resources
中的 application.properties
将被拾取,因为 test classpath 将在 main[= 之前90=] class路径。但是,如果你 运行 你的测试像 Eclipse/STS 中的 Run as JUnit Test
,src/main/resources
中的 application.properties
将被拾取,因为 main class路径先于测试 class路径.
打开菜单栏即可查看 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\workspace-spring-tool-suite-4-4.5.1.RELEASE\project_name\bin\test;
有没有看到classpathxxx\main在前,然后是 xxx\test?对了,都是关于class路径 :-)
旁注:
请注意,启动配置中覆盖的属性(例如,在 Spring 工具套件 IDE 中)优先于 application.properties.
更改顺序:
现在,Spring 中的一切都是可配置的。您可以更改构建 class 路径,使 xxx\test 先出现,然后是 xxx\main。
只需转到 Project > Properties > Java Build Path > Order and Export
,更改构建 class 路径顺序,将任何 test 文件夹放在首位,例如:
就是这样!
更好的解决方案
不过,在测试时,更好的解决方案是激活 src/test/resources/application-{profile}.properties
(其中 profile
可以测试),例如 src/main/resources/application.properties
中的以下内容:
spring.profiles.active=test
这更简洁,让您可以完全控制在做什么时激活什么配置文件。
如果您正在使用 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);
}
}
我想你也可以用这个:
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
当使用 spring.config.additional-location 配置自定义配置位置时,除了默认位置外还会使用它们。
文件优先
详情请参考here。
您可以在 src/test/resources/META-INF 中创建一个 spring.factories 文件,在 src/test/java 中创建一个 EnvironmentPostProcessor 实现 class。
spring.factories
喜欢
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.test.YourTestPropertiesConfig
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);
}
}
我有一个 Spring-Boot 应用程序,其中默认属性设置在 class 路径 (src/main/resources/application.properties) 的 application.properties
文件中。
我想用 test.properties
文件中声明的属性覆盖我的 JUnit 测试中的一些默认设置 (src/test/resources/test.properties)
我通常有一个专门的配置 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 {
}
我最初认为在 TestConfig class 中使用 @PropertySource("classpath:test.properties")
可以解决问题,但这些属性不会覆盖 application.properties 设置(参见 Spring-Boot参考文档 - 23. Externalized Configuration).
然后我尝试在调用测试时使用-Dspring.config.location=classpath:test.properties
。那是成功的 - 但我不想为每个测试执行设置此系统 属性。因此我把它放在代码中
@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {
static {
System.setProperty("spring.config.location", "classpath:test.properties");
}
}
不幸的是,这又一次没有成功。
关于如何使用 test.properties
覆盖 JUnit 测试中的 application.properties
设置,一定有一个简单的解决方案,我一定是忽略了。
您可以使用 @TestPropertySource
覆盖 application.properties
中的值。从它的 javadoc:
test property sources can be used to selectively override properties defined in system and application property sources
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {
}
您还可以使用 meta-annotations 来外部化配置。例如:
@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 { }
否则我们可能会更改默认的 属性 配置器名称,设置 属性 spring.config.name=test
然后拥有 class-path 资源
src/test/test.properties
我们 org.springframework.boot.SpringApplication
的本机实例将从这个分离的 test.properties 中自动配置,忽略应用程序属性;
好处:自动配置测试;
缺点:在 C.I 处暴露 "spring.config.name" 属性。图层
参考:http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.config.name=application # Config file name
Spring 引导自动加载 src/test/resources/application.properties
,如果使用以下注释
@RunWith(SpringRunner.class)
@SpringBootTest
因此,将 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)
[更新:重写某些属性以进行测试]
- 添加
src/main/resources/application-test.properties
. - 用
@ActiveProfiles("test")
注释测试class。
这会将 application.properties
和 然后 application-test.properties
属性加载到测试用例的应用程序上下文中,按照定义的规则 here。
TLDR:
所以我所做的是拥有标准 src/main/resources/application.properties
和 src/test/resources/application-default.properties
,我在其中覆盖了所有测试的一些设置。
对于电源开发人员:
为了 change/use 更容易地改变 spring 配置文件,我现在有一个 application-default.yaml
来声明我想使用的配置文件。
此文件未提交,因此每个开发人员都可以选择激活配置文件和需求(例如功能)的方式 he/she 正在处理。
spring:
profiles:
include:
- local
- devlocal
- wip
# - kafka@docker
---
spring.profiles: wip
# ... overriding 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。
您还可以在编写 JUnit 的 src/test/resources 中创建一个 application.properties 文件。
另一种适用于覆盖测试中的一些属性的方法,如果您使用 @SpringBootTest
注释:
@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
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`
如果您像我一样,在 src/main/resources
和 src/test/resources
中有相同的 application.properties
,并且您想知道 为什么 application.properties
在你的测试文件夹中 没有覆盖 在你的主要资源中的 application.properties
,继续阅读...
简单说明:
如果您在 src/main/resources
下有 application.properties
并且在 src/test/resources
下有相同的 application.properties
,application.properties
被拾取, 取决于关于您如何 运行 测试 。文件夹 structure src/main/resources
和 src/test/resources
是 Maven 架构约定,所以如果你 运行 你的测试像 mvnw test
甚至 gradlew test
,src/test/resources
中的 application.properties
将被拾取,因为 test classpath 将在 main[= 之前90=] class路径。但是,如果你 运行 你的测试像 Eclipse/STS 中的 Run as JUnit Test
,src/main/resources
中的 application.properties
将被拾取,因为 main class路径先于测试 class路径.
打开菜单栏即可查看 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\workspace-spring-tool-suite-4-4.5.1.RELEASE\project_name\bin\test;
有没有看到classpathxxx\main在前,然后是 xxx\test?对了,都是关于class路径 :-)
旁注: 请注意,启动配置中覆盖的属性(例如,在 Spring 工具套件 IDE 中)优先于 application.properties.
更改顺序:
现在,Spring 中的一切都是可配置的。您可以更改构建 class 路径,使 xxx\test 先出现,然后是 xxx\main。
只需转到 Project > Properties > Java Build Path > Order and Export
,更改构建 class 路径顺序,将任何 test 文件夹放在首位,例如:
就是这样!
更好的解决方案
不过,在测试时,更好的解决方案是激活 src/test/resources/application-{profile}.properties
(其中 profile
可以测试),例如 src/main/resources/application.properties
中的以下内容:
spring.profiles.active=test
这更简洁,让您可以完全控制在做什么时激活什么配置文件。
如果您正在使用 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);
}
}
我想你也可以用这个:
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
当使用 spring.config.additional-location 配置自定义配置位置时,除了默认位置外还会使用它们。
文件优先
详情请参考here。
您可以在 src/test/resources/META-INF 中创建一个 spring.factories 文件,在 src/test/java 中创建一个 EnvironmentPostProcessor 实现 class。
spring.factories
喜欢
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.test.YourTestPropertiesConfig
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);
}
}