在 Spring Boot Test 中加载不同的 application.yml

Posted

技术标签:

【中文标题】在 Spring Boot Test 中加载不同的 application.yml【英文标题】:Load different application.yml in SpringBoot Test 【发布时间】:2016-12-07 07:15:50 【问题描述】:

我正在使用一个运行我的 src/main/resources/config/application.yml 的 Spring Boot 应用程序。

当我运行我的测试用例时:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class MyIntTest

测试代码仍然运行我的 application.yml 文件来加载属性。 我想知道在运行测试用例时是否可以运行另一个 *.yml 文件。

【问题讨论】:

【参考方案1】:

您可以在src/test/resources/config/application.yml 文件中设置您的测试属性。 Spring Boot 测试用例将从 test 目录中的application.yml 文件中获取属性。

config 文件夹是在 Spring Boot 中预定义的。

根据文档:

如果你不喜欢 application.properties 作为配置文件名,你可以通过指定 spring.config.name 环境属性来切换到另一个文件名。您还可以使用 spring.config.location 环境属性(以逗号分隔的目录位置或文件路径列表)来引用显式位置。以下示例显示了如何指定不同的文件名:

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

application.yml 也是如此

文档:

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-application-property-files

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files

【讨论】:

其实一开始,测试用的yml文件就在那个路径下,即“src/test/resources/config/application.yml”。但不知道为什么没有当我运行我的测试用例时加载 我使用的是 Intellij IDEA,但在我的 <testResource>pom.xml 中没有 <include>**/*.yml</include>。由于 IDEA 使用 pom.xml 配置作为编译代码的主要模型(即使在 mvn 运行之外!),这意味着我的 src/test/resources/application.yml 没有被我的测试选中,因为它不存在于 @ 987654336@. 这应该被标记为正确答案,因为它是 YAML 文件的情况。我已向 Spring Boot Team 确认 TestPropertySource 不支持 YAML 文件。Spring Boot JIRA 有谁知道在测试时如何强制springboot替换yml中的@placeholder@?为什么他们强迫我静态输入数据? 请注意,子目录的名称 (config) 不是任意的,而是预定义的。详情参见Spring Boot documentation 和 ConfigFileApplicationListener.load() 方法的源代码。【参考方案2】:

Spring-boot 框架允许我们提供 YAML 文件作为 .properties 文件 的替代,这很方便。属性文件可以在资源文件夹中的 application.yml 文件中以 YAML 格式提供,spring-boot 会自动占用它。请记住,yaml 格式必须保持空格正确正确阅读。

您可以使用@Value("$property") 从 YAML 文件中注入值。 还可以提供 Spring.active.profiles 来区分不同环境的不同 YAML,以便于部署。

出于测试目的,测试 YAML 文件可以命名为 application-test.yml 并放置在测试的资源文件夹中目录。

如果您指定application-test.yml 并在.yml 中提供spring 测试配置文件,那么您可以使用@ActiveProfiles('test') 注释指示spring 从应用程序测试中获取配置。您指定的 yml

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ApplicationTest.class)
@ActiveProfiles("test")
public class MyTest 
 ...

如果您使用的是 JUnit 5,则不需要其他注释,因为 @SpringBootTest 已经包含 springrunner 注释。保留一个单独的主 ApplicationTest.class 使我们能够为测试提供单独的配置类,并且我们可以通过将它们从测试主类中的组件扫描中排除来防止加载默认配置 bean。您还可以提供要在此处加载的配置文件。

@SpringBootApplication(exclude=SecurityAutoConfiguration.class)
public class ApplicationTest 
 
    public static void main(String[] args) 
        SpringApplication.run(ApplicationTest.class, args);
    

这里是有关使用 YAML 代替 .properties 文件的 Spring 文档链接:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

【讨论】:

【参考方案3】:

Lu55 选项 1 如何...

在单独的资源文件夹中添加仅测试 application.yml。

├── 主要 │ ├── java │ └── 资源 │ ├── application.yml └── 测试 ├── java └── 资源 └── application.yml

在此项目结构中,如果main下的代码正在运行,则加载main下的application.yml,在测试中使用被测的application.yml。

若要设置此结构,请添加一个新的包文件夹 test/recources(如果不存在)。

Eclipse 右键单击​​您的项目 -> 属性 -> Java 构建路径 -> 源选项卡 -> (右侧对话框)“添加文件夹...”

在源文件夹选择内 -> 标记测试 -> 点击“创建新文件夹...”按钮 -> 在 Textfeld 中输入“资源” -> 点击“完成”按钮。

按下“Finisch”按钮后,您可以看到源文件夹 projectname/src/test/recources (new)

可选:为 Project Explorer 视图排列文件夹顺序。 单击 Order and Export Tab 标记并将 projectname/src/test/recources 移动到底部。 申请并关闭 !!!清理项目!!! Eclipse -> 项目 -> 清理 ...

现在有一个单独的 yaml 用于测试和主应用程序。

【讨论】:

【参考方案4】:

一个简单的使用配置

@TestPropertySource 和 属性

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(properties = "spring.config.location=classpath:another.yml")
public class TestClass 


    @Test

    public void someTest() 
    

【讨论】:

【参考方案5】:

这可能被视为选项之一。现在,如果你想加载一个 yml 文件(在应用上述注释时默认没有加载),诀窍是使用

@ContextConfiguration(classes= ..., initializers=ConfigFileApplicationContextInitializer.class)

这是一个示例代码

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@DirtiesContext
@ContextConfiguration(classes= DataSourceTestConfig.class, initializers = ConfigFileApplicationContextInitializer.class)
public class CustomDateDeserializerTest 


    private ObjectMapper objMapper;

    @Before
    public void setUp() 
        objMapper = new ObjectMapper();

    

    @Test
    public void test_dateDeserialization() 

    

再次确保 setup config java 文件 - 此处为 DataSourceTestConfig.java 包含以下属性值。

@Configuration
@ActiveProfiles("test")
@TestPropertySource(properties =  "spring.config.location=classpath:application-test.yml" )
public class DataSourceTestConfig implements EnvironmentAware 

    private Environment env;

    @Bean
    @Profile("test")
    public DataSource testDs() 
       HikariDataSource ds = new HikariDataSource();

        boolean isAutoCommitEnabled = env.getProperty("spring.datasource.hikari.auto-commit") != null ? Boolean.parseBoolean(env.getProperty("spring.datasource.hikari.auto-commit")):false;
        ds.setAutoCommit(isAutoCommitEnabled);
        // Connection test query is for legacy connections
        //ds.setConnectionInitSql(env.getProperty("spring.datasource.hikari.connection-test-query"));
        ds.setPoolName(env.getProperty("spring.datasource.hikari.pool-name"));
        ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
        long timeout = env.getProperty("spring.datasource.hikari.idleTimeout") != null ? Long.parseLong(env.getProperty("spring.datasource.hikari.idleTimeout")): 40000;
        ds.setIdleTimeout(timeout);
        long maxLifeTime = env.getProperty("spring.datasource.hikari.maxLifetime") != null ? Long.parseLong(env.getProperty("spring.datasource.hikari.maxLifetime")): 1800000 ;
        ds.setMaxLifetime(maxLifeTime);
        ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
        ds.setPoolName(env.getProperty("spring.datasource.hikari.pool-name"));
        ds.setUsername(env.getProperty("spring.datasource.username"));
        ds.setPassword(env.getProperty("spring.datasource.password"));
        int poolSize = env.getProperty("spring.datasource.hikari.maximum-pool-size") != null ? Integer.parseInt(env.getProperty("spring.datasource.hikari.maximum-pool-size")): 10;
        ds.setMaximumPoolSize(poolSize);

        return ds;
    

    @Bean
    @Profile("test")
    public JdbcTemplate testJdbctemplate() 
        return new JdbcTemplate(testDs());
    

    @Bean
    @Profile("test")
    public NamedParameterJdbcTemplate testNamedTemplate() 
        return new NamedParameterJdbcTemplate(testDs());
    

    @Override
    public void setEnvironment(Environment environment) 
        // TODO Auto-generated method stub
        this.env = environment;
    

【讨论】:

【参考方案6】:

如果您需要完全替换生产版application.yml,则将其测试版本放在相同的路径但在测试环境中(通常是src/test/resources/

但如果您需要覆盖或添加一些属性,那么您几乎没有选择。

选项 1:将测试 application.yml 放在 src/test/resources/config/ 目录中,正如 @TheKojuEffect 在他的 answer 中所建议的那样。

选项 2:使用 profile-specific properties:在您的 src/test/resources/ 文件夹中创建 application-test.yml 并且:

在您的测试类中添加@ActiveProfiles 注释:

@SpringBootTest(classes = Application.class)
@ActiveProfiles("test")
public class MyIntTest 

或者在@SpringBootTest注解中设置spring.profiles.active属性值:

@SpringBootTest(
        properties = ["spring.profiles.active=test"],
        classes = Application.class,
)
public class MyIntTest 

这不仅适用于@SpringBootTest,还适用于@JsonTest@JdbcTests@DataJpaTest 和其他切片测试注释。

您可以根据需要设置任意数量的配置文件 (spring.profiles.active=dev,hsqldb) - 请参阅Profiles 上的文档中的更多详细信息。

【讨论】:

【参考方案7】:

从 Spring 4.1 开始,我们可以直接在 application.yml 中使用 @TestPropertySource 注解设置属性。

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = "yoursection.yourparameter=your_value")
public MyIntTest

 //your test methods

只需将您的 yaml 参数转换为完整的属性结构。 例如: 如果 application.yml 的内容如下所示

yoursection:
  yourparameter:your_value

然后进入@TestPropertySource 的值将是,

yoursection.yourparameter=your_value

【讨论】:

【参考方案8】:

我们可以使用@SpringBootTest注解从src\main\java\com加载yml文件...因此当我们执行单元测试时,所有的属性都已经存在于配置属性类中了。

@RunWith(SpringRunner.class)
@SpringBootTest
public class AddressFieldsTest 

    @InjectMocks
    AddressFieldsValidator addressFieldsValidator;

    @Autowired
    AddressFieldsConfig addressFieldsConfig;
    ...........

    @Before
    public void setUp() throws Exception
        MockitoAnnotations.initMocks(this);
        ReflectionTestUtils.setField(addressFieldsValidator,"addressFieldsConfig", addressFieldsConfig);
    


如果您的配置很少,我们可以使用@Value 注解,否则我们可以使用配置属性类。例如

@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "address.fields.regex")
public class AddressFieldsConfig 

    private int firstName;
    private int lastName;
    .........

【讨论】:

【参考方案9】:

你可以使用@TestPropertySource来加载不同的properties/yaml文件

@TestPropertySource(locations="classpath:test.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class MyIntTest


或者,如果您想覆盖您只能使用特定的属性/yaml

@TestPropertySource(
        properties = 
                "spring.jpa.hibernate.ddl-auto=validate",
                "liquibase.enabled=false"
        
)

【讨论】:

我试过使用这个注解,但在测试中它仍然寻找application.yml而不是我指定的那个。 如前所述,这仅适用于 .properties 文件,因为注释不支持 yaml 文件。这真的不是问题的答案。【参考方案10】:

一种选择是使用配置文件。创建一个名为 application-test.yml 的文件,将这些测试所需的所有属性移动到该文件,然后将 @ActiveProfiles 注释添加到您的测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@ActiveProfiles("test") // Like this
public class MyIntTest

请注意,它将额外加载 application-test.yml,因此 application.yml 中的所有属性仍将被应用。如果您不希望这样,也可以使用这些配置文件,或者在您的 application-test.yml 中覆盖它们。

【讨论】:

这是正确答案。注释 TestPropertySource 仅适用于 .properties 或 .xml 文件。请参阅docs.spring.io/spring/docs/current/javadoc-api/org/…中的“支持的文件格式部分” 这很好用,但如果你这样做,我建议你也有一些使用“test”配置文件的测试。测试应用程序 yaml 与实际应用程序 yml 合并这一事实可能会导致应用程序在单元测试中运行良好,但在独立运行时会出现问题。 我想这是测试配置文件是否为配置文件正确格式化的最佳方法。这意味着我们需要 N 个空测试,只需为 N 个配置文件中的每一个加载 Spring 上下文来测试,还有其他想法吗?【参考方案11】:

看到这个:Spring @PropertySource using YAML

我认为第三个答案有你想要的,即有一个单独的 POJO 来将你的 yaml 值映射到:

@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties 
    private String url;
    private String username;
    private String password;
...

然后用这个注释你的测试类:

@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService 

    @Autowired private DbProperties dbProperties;


【讨论】:

以上是关于在 Spring Boot Test 中加载不同的 application.yml的主要内容,如果未能解决你的问题,请参考以下文章

如何在 spring-boot 配置中加载 application.yaml 配置以进行硒测试

无法在 Spring Boot 中加载外部属性

如何在没有 spring-boot 的情况下在 spring-webflux 中加载配置?

spring - @ContextConfiguration 无法在 src/test/resources 中加载配置文件

如何在 Spring Boot 测试中加载仅添加命名组件的基本 Spring Application-Context?

如何通过Spring Boot在MongoDB中加载初始数据?