简体   繁体   English

在 Junit 测试中覆盖默认的 Spring-Boot application.properties 设置

[英]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 ] [更新:覆盖某些属性进行测试]

  1. Add src/main/resources/application-test.properties .添加src/main/resources/application-test.properties
  2. Annotate test class with @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"})

TLDR:域名注册地址:

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在这里我覆盖了我所有测试的一些设置。

For power-developers:对于电源开发人员:

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 

Whole Story整个故事

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.propertiessrc/main/resourcessrc/test/resources ,和你想知道为什么application.properties在测试文件夹不重写application.properties在主资源,继续阅读……

Simple explanation:简单解释:

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/resourcessrc/test/resources是 Maven 架构约定,因此如果您像mvnw test甚至gradlew test一样运行gradlew testsrc/test/resourcesapplication.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/resourcesapplication.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。

Change the order:更改顺序:

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!就是这样!

Better solution更好的解决方案

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该文件将具有优先权

Please refer here for more details.请参阅此处了解更多详情。

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:和两个属性文件:

  • src/main/resources/application.yml src/main/resources/application.yml
  • src/test/resources/application-test.yml src/test/resources/application-test.yml

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使用

  • properties declared with .yaml file-ending.yaml文件结尾声明的属性
  • Spring-Boot 2.7 Spring-Boot 2.7
  • and multiple.yaml files in the classpath和类路径中的多个.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.

相关问题 使用动态值覆盖 Junit 测试中的默认 Spring-Boot application.properties 设置 - Override default Spring-Boot application.properties settings in Junit Test with dynamic value 用application.properties覆盖默认的Spring-Boot application.properties - Override default Spring-Boot application.properties with application.properties 覆盖application.properties以在Spring-boot应用程序中进行集成测试 - Override application.properties for integration tests in spring-boot app 如何在 Spring-Boot 的生产过程中覆盖 application.properties? - How to override application.properties during production in Spring-Boot? Spring-boot - 参数化测试 - 访问MethodSource中的Application.properties - Spring-boot - Parameterized Test - Access Application.properties in MethodSource Spring Boot 访问 application.properties 以进行 JUnit 测试 - Spring Boot accessing application.properties for JUnit Test 如何在Spring Boot集成测试中覆盖application.properties? - How to override application.properties in Spring Boot integration test? 在Junit测试中无法覆盖Spring-Boot应用程序属性 - Cannot overrid Spring-Boot application properties in Junit Test spring-boot application.properties中的环境变量错误 - Environment Variables in spring-boot application.properties error 春季启动application.properties问题-bug - spring-boot application.properties question -bug
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM