ChatGPT解决这个技术问题 Extra ChatGPT

在 Junit Test 中覆盖默认 Spring-Boot application.properties 设置

我有一个 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 设置,必须有一个简单的解决方案,我必须忽略它。

如果您只需要配置几个属性,则可以使用新的 @DynamicPropertySource 注解。 stackoverflow.com/a/60941845/8650621
我使用 ReflectionTestUtils.setField(myService, "myPropery", myPropertyValue);

A
Andy Wilkinson

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

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

例如:

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

}

而已。谢谢。不幸的是,它在 ExampleApplication.class 上使用时不起作用,所以我必须在每个测试类上设置它。那正确吗?
另请注意,@TestPropertySource 可以接受 properties 参数来覆盖某些内联属性,例如 @TestPropertySource(properties = "myConf.myProp=valueInTest"),如果您不想要全新的属性文件,这很有用。
您可以指定数组中的多个文件,也可以指定文件系统上的文件(但请记住它们可能无法在 CI 服务器上运行):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
请注意,@SpringApplicationConfiguration 已被弃用,您应该使用 @SpringBootTest
如果文件 src/test/resources/application-test.properties 可以用于单元测试,那就太好了。
M
Mohnish

如果使用了以下注解,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.propertiesthen application-test.properties 属性加载到测试用例的应用程序上下文中。

演示 - https://github.com/mohnish82/so-spring-boot-testprops


不确定在类路径中有两个 application.properties 文件(一个在 src/main/resources 中,一个在 src/test/resources 中)是否是个好主意。谁保证两者都会被拿走,哪一个会先被拿走?
@FrVaBe Spring 将保证它!始终加载主配置文件属性。然后在测试阶段,加载测试属性,添加/覆盖新的/现有的属性。如果您不喜欢保留两个同名文件,则可以在 src/main/resources 中添加 application-test.properties 并将 test 指定为测试用例中的活动配置文件。
Spring 不提供任何保证。构建工具将在测试期间使用测试资源来支持主要资源。但在测试 application.properties 的情况下,主 application.properties 将被忽略。这不是我想要的,因为主要的包含几个有用的默认值,我只需要在测试期间覆盖其中的一些(我不想在测试部分复制整个文件)。请参阅here
您是对的,在测试阶段仅加载 src/test/resources/application.properties 中定义的属性,src/main/resources/application.properties 被忽略。
如果您到目前为止不使用配置文件,则不需要专用的“测试”配置文件。只需将您的测试属性命名为 application-default.properties,它们就会被考虑,因为您正在自动运行“默认”配置文件(如果未声明任何其他配置文件)。
M
Michael Lihs

您还可以使用 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 { }

N
Nima Ajdari

如果您使用 @SpringBootTest 注释,另一种适合覆盖测试中的一些属性的方法:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})

SpringBootTest 是否加载 application.properties 文件?
@TuGordoBello 是的
j
jumping_monkey

如果您像我一样,并且在 src/main/resourcessrc/test/resources 中具有相同的 application.properties,并且您想知道为什么您的测试文件夹中的 application.properties 没有覆盖 strong> 主要资源中的 application.properties,请继续阅读...

简单解释:

如果您在 src/main/resources 下有 application.properties,在 src/test/resources 下有相同的 application.properties(其中 application.properties 会被选中),取决于您运行测试的方式。文件夹 structure src/main/resourcessrc/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=测试

这更简洁,让您可以完全控制在做什么时激活什么配置文件。


我发现这种方法缺乏,因为在您的测试中定义配置文件将删除通过 CI 和其他环境中的 -Dspring.profiles.active=... 动态调整此选项的选项,这些环境可能需要您可能不想通过 -D 覆盖的其他配置,因为这变成了很乏味。毕竟,只有 集成 测试才需要启动 spring 上下文,并且这些测试可能依赖于外部资源,这些资源与它们运行的环境不同。
嘿@elonderin,感谢您的评论。如果有所有人通用的配置,我将它们插入 application.properties。此后,如果我在 local 上开发并执行 testspring.profiles.active=local, test。如果我在 pre-prod,它变成 spring.profiles.active=pre-prod, test。这是你想要的吗?
这应该是公认的答案。显然,test/application.properties 不会覆盖 main/application.properties。
e
elonderin

TLDR:

所以我所做的是拥有标准的 src/main/resources/application.propertiessrc/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 boot 2.4 开始,power-developer 方式已被弃用,请参阅 spring.io/blog/2020/08/14/…
F
Felipe Desiderati

如果您使用的是 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 注释。
不使用测试容器时这不起作用
s
sendon1982

我想你也可以使用这个:

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

当使用 spring.config.additional-location 配置自定义配置位置时,除了默认位置之外,还会使用它们。

该文件将具有优先权

有关详细信息,请参阅 here


这对我有用,非常好。 @TestPropertySource(properties = "spring.config.additional-location=file:/Users/..")
D
D. Soloviev

否则,我们可能会更改默认属性配置器名称,设置属性 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 对我来说不是一个选项,因为我只想覆盖测试中的 一些 原始配置值。
我一直在寻找一种方法来进行不加载 src/main/resources/application.properties 的单个测试,就是这样。创建一个文件: src/test/resources/empty.properties 并将注释添加到应该忽略主要属性的测试中。 @TestPropertySource(properties="spring.config.name=empty")
如何为每个 junit 测试方法设置特定的属性值?
H
Hilal Aissani
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);
    }
}

P
PragmaticFire

您还可以在编写 JUnit 的 src/test/resources 中创建 application.properties 文件。


这有什么帮助? ^^
这是他不想要的……