我有一个 Spring-Boot 应用程序,其中默认属性设置在类路径 (src/main/resources/application.properties) 的 application.properties
文件中。
我想用 test.properties
文件 (src/test/resources/test.properties) 中声明的属性覆盖我的 JUnit 测试中的一些默认设置
我通常有一个专门的配置类用于我的 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 类中使用 @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:
测试属性源可用于选择性地覆盖系统和应用程序属性源中定义的属性
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {
}
如果使用了以下注解,Spring Boot 会自动加载 src/test/resources/application.properties
@RunWith(SpringRunner.class)
@SpringBootTest
因此,将 test.properties
重命名为 application.properties
以利用自动配置。
如果您只需要加载属性文件(到环境中),您还可以使用以下内容,如此处所述
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
[更新:覆盖某些属性进行测试]
添加 src/main/resources/application-test.properties。使用 @ActiveProfiles("test") 注释测试类。
根据定义的规则 here,这会将 application.properties
和 then application-test.properties
属性加载到测试用例的应用程序上下文中。
演示 - https://github.com/mohnish82/so-spring-boot-testprops
application.properties
文件(一个在 src/main/resources
中,一个在 src/test/resources
中)是否是个好主意。谁保证两者都会被拿走,哪一个会先被拿走?
src/main/resources
中添加 application-test.properties
并将 test
指定为测试用例中的活动配置文件。
src/test/resources/application.properties
中定义的属性,src/main/resources/application.properties
被忽略。
application-default.properties
,它们就会被考虑,因为您正在自动运行“默认”配置文件(如果未声明任何其他配置文件)。
您还可以使用 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 { }
如果您使用 @SpringBootTest
注释,另一种适合覆盖测试中的一些属性的方法:
@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
SpringBootTest
是否加载 application.properties 文件?
如果您像我一样,并且在 src/main/resources
和 src/test/resources
中具有相同的 application.properties
,并且您想知道为什么您的测试文件夹中的 application.properties
没有覆盖 strong> 主要资源中的 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 类路径将在 main 类路径之前。但是,如果您在 Eclipse/STS 中运行类似 Run as JUnit Test
的测试,则 src/main/resources
中的 application.properties
将被选中,因为 main 类路径在 test 类路径之前。
您可以通过打开菜单栏 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;
您是否看到类路径 xxx\main 先出现,然后是 xxx\test?对,这都是关于类路径的:-)
旁注:请注意,在启动配置中覆盖的属性(例如在 Spring Tool Suite IDE 中)优先于 application.properties。
更改顺序:
现在,一切都可以在 Spring 中进行配置。您可以更改构建类路径,以便首先出现 xxx\test,然后是 xxx\main。
只需转到 Project > Properties > Java Build Path > Order and Export
,通过将任何 test 文件夹放在首位来更改构建类路径顺序,例如:
https://i.stack.imgur.com/OLBez.png
就是这样!
更好的解决方案
不过,更好的解决方案是在测试时激活 src/test/resources/application-{profile}.properties
(其中可以测试 profile
),例如 src/main/resources/application.properties
中的以下内容:
spring.profiles.active=测试
这更简洁,让您可以完全控制在做什么时激活什么配置文件。
-Dspring.profiles.active=...
动态调整此选项的选项,这些环境可能需要您可能不想通过 -D
覆盖的其他配置,因为这变成了很乏味。毕竟,只有 集成 测试才需要启动 spring 上下文,并且这些测试可能依赖于外部资源,这些资源与它们运行的环境不同。
application.properties
。此后,如果我在 local
上开发并执行 test
,spring.profiles.active=local, test
。如果我在 pre-prod,它变成 spring.profiles.active=pre-prod, test
。这是你想要的吗?
TLDR:
所以我所做的是拥有标准的 src/main/resources/application.properties
和 src/test/resources/application-default.properties
,我在其中覆盖了我所有测试的一些设置。
对于电源开发人员:
为了更轻松地更改/使用不同的弹簧配置文件,我现在有一个 application-default.yaml
来声明我要使用的配置文件。该文件未提交,因此每个开发人员都可以选择他/她正在处理的配置文件和需求(例如功能)的激活方式。
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。
如果您使用的是 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);
}
}
@Testcontainers
注释。
我想你也可以使用这个:
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
当使用 spring.config.additional-location 配置自定义配置位置时,除了默认位置之外,还会使用它们。
该文件将具有优先权
有关详细信息,请参阅 here。
否则,我们可能会更改默认属性配置器名称,设置属性 spring.config.name=test
,然后使用类路径资源 src/test/test.properties
,我们的 org.springframework.boot.SpringApplication
本地实例将从这个单独的 test.properties 自动配置,忽略应用程序属性;
好处:测试的自动配置;
缺点:在 CI 层暴露“spring.config.name”属性
参考:http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.config.name=application #配置文件名
application.properties
对我来说不是一个选项,因为我只想覆盖测试中的 一些 原始配置值。
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/test/resources/META-INF 中创建一个 spring.factories 文件,在 src/test/java 中创建一个 EnvironmentPostProcessor 实现类。
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);
}
}
您还可以在编写 JUnit 的 src/test/resources 中创建 application.properties 文件。
@TestPropertySource
可以接受properties
参数来覆盖某些内联属性,例如@TestPropertySource(properties = "myConf.myProp=valueInTest")
,如果您不想要全新的属性文件,这很有用。@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
@SpringApplicationConfiguration
已被弃用,您应该使用@SpringBootTest
src/test/resources/application-test.properties
可以用于单元测试,那就太好了。