覆盖默认的Spring-Boot应用程序。属性设置在Junit测试

我有一个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")可以达到目的,但这些属性不会覆盖应用程序。属性设置(参见Spring-Boot参考Doc - 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,我必须忽略。

345419 次浏览

你可以使用@TestPropertySource来覆盖application.properties中的值。从它的javadoc:

测试属性源可用于选择性地覆盖系统和应用程序属性源中定义的属性

例如:

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


}

你也可以使用元注释来具体化配置。例如:

@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,然后拥有类路径资源 src/test/test.properties我们的本地实例org.springframework.boot.SpringApplication将从这个分离的测试中自动配置。属性,忽略应用程序属性

优点:自动配置测试;

缺点:在C.I.层暴露“spring.config.name”属性

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

spring.config.name=application #配置文件名

如果使用以下注释,Spring Boot会自动加载src/test/resources/application.properties

@RunWith(SpringRunner.class)
@SpringBootTest

因此,将test.properties重命名为application.properties以利用自动配置。

如果你< em >只需要加载属性文件(到环境中),你也可以使用下面的方法,如所解释的在这里 . 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

TLDR:

所以我所做的就是有标准的src/main/resources/application.properties和一个src/test/resources/application-default.properties,其中我覆盖了我所有测试的一些设置。

power-developers:

为了更容易地改变/使用不同的spring概要文件,我现在有一个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

您也可以创建一个应用程序。在src/test/resources中的属性文件中,你的junit是在这里编写的。

另一种适用于覆盖测试中的一些属性的方法,如果你使用@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/resourcessrc/test/resources中有相同的application.properties,并且你是想知道,为什么你测试文件夹中的application.properties不是最重要的,而你主要资源中的application.properties,请继续阅读…

简单的解释:

如果你在src/main/resources下有application.properties,在src/test/resources下有相同的application.properties,其中application.properties被拾取,src/main/resources4。文件夹src/main/resources5 src/main/resourcessrc/test/resources,是一个Maven架构约定,所以如果你像mvnw test或甚至gradlew test那样运行测试,src/test/resources中的application.properties将被选中,因为src/main/resources6类路径将在src/main/resources7类路径之前。但是,如果你在Eclipse/STS中像src/main/resources1那样运行测试,src/main/resources中的application.properties将被拾取,因为src/main/resources7类路径在src/main/resources6类路径之前

你可以通过打开菜单栏 Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line"来检查它。

你会看到类似这样的东西:

XXXbin\javaw.exe -ea -Dfile. exe编码= utf - 8类路径< br > XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \主要;< br > XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \测试;< br >

你看到类路径 xxx \主要先出现,然后是xxx \测试吗?对,这都是关于类路径的:-)

< p > < em >附注: 请注意,在启动配置中覆盖的属性(例如在Spring Tool Suite IDE中)优先于application.properties.

.properties.

.properties.

.properties.

改变顺序:

现在,在Spring中一切都是可配置的。你可以改变构建类路径,让xxx \测试先出现,然后是xxx \主要

简单地转到Project > Properties > Java Build Path > Order and Export,通过将任何测验文件夹放在前面来更改构建类的路径顺序,例如:

enter image description here

就是这样!

更好的解决方案

不过,在测试时,一个更好的解决方案是激活src/test/resources/application-{profile}.properties(其中profile可以被测试),例如下面的src/main/resources/application.properties:

spring.profiles.active =测试

这更整洁,并让您完全控制在做什么时激活哪个配置文件。

如果您正在使用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配置自定义配置位置时。附加位置,它们用于默认位置之外。

该文件将具有优先级

更多细节请参考在这里

可以创建spring。src/test/resources/META-INF中的factories文件和src/test/java中的EnvironmentPostProcessor Implementation类。
spring.factories像< / p >

# 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);
}
}

这对我来说很管用:

我的测试:

@SpringBootTest
@TestPropertySource(properties = "spring.config.additional-location=classpath:application-test.yml")
class EngineApplicationTests {
@Test
void contextLoads() {
}
}

我的版本:

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")
}

我的gradle文件中唯一的测试依赖项:

testImplementation 'org.springframework.boot:spring-boot-starter-test'

我的身材里也有这个。gradle文件:

test {
useJUnitPlatform()
}

和两个属性文件:

  • src / main /资源/ application.yml
  • src /测试/资源/ application-test.yml

在这个设置中,应用程序测试。yml绝对只覆盖application.yml中的值。我不需要重复应用程序中的属性值。在application-test.yml。应用程序测试。Yml确实扩展了application.yml。

使用

  • 使用.yaml file-ending声明的属性
  • Spring-Boot 2.7
  • 类路径中有多个.yaml文件

我注意到@TestPropertySource(locations)的优先级没有像.properties文件那样应用。

我遇到的问题是,Spring一直加载所有.yaml属性(特别是那些来自生产)和压倒一切的的属性意味着测试的值指定为prod。

我们提出了重写配置抓取机制的解决方法,只指定application-test.yaml作为唯一使用的属性,如下所示:

@TestPropertySource(properties = "spring.config.location=classpath:/application-test.yaml")