在SpringBoot测试中加载不同的application.yml


73

我正在使用运行我的src / main / resources / config / application.yml的spring boot应用程序。

当我通过以下方式运行测试用例时:

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

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

Answers:


86

一种选择是使用配置文件。创建一个名为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中覆盖它们。


6
这是正确的答案。注释TestPropertySource仅适用于.properties或.xml文件。请参阅docs.spring.io/spring/docs/current/javadoc-api/org/…中的
Sym-Sym

1
这很好用,但是如果您这样做,我建议您也进行一些使用“测试”配置文件的测试。测试应用程序yaml与实际应用程序yml合并的事实可能会导致该应用程序在单元测试中运行良好,但是在独立运行时会出现问题。
Joman68年

我想这是测试配置文件的格式是否正确的最佳方法。这意味着我们将需要N个测试空测试,而只是为每个N个配置文件加载Spring上下文来测试它,还有其他想法吗?
Dio

25

您可以在src/test/resources/config/application.yml文件中设置测试属性。Spring Boot测试用例将从测试目录中的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


3
实际上,最初,用于测试的yml文件就是该路径,即“ src / test / resources / config / application.yml”。但是我不知道为什么在运行测试用例时为什么不加载它
Exia

我使用IntelliJ IDEA的,并没有<include>**/*.yml</include><testResource>我的pom.xml。由于IDEA使用pom.xml配置作为编译代码的主要模型(甚至在mvn运行之外!),这意味着src/test/resources/application.yml我的测试没有被我接受,因为它不在中target/test-classes
Rossiar

4
应该将其标记为正确答案,因为YAML文件就是这种情况。我已经与Spring Boot Team确认TestPropertySource不支持YAML文件。春季靴子JIRA
塞尔曼

有谁知道如何在测试时强制springboot替换yml中的@ placeholder @?为什么他们强迫我静态输入数据?
西蒙逻辑

2
请注意,子目录(config)的名称不是任意的,而是预定义的。有关详细信息,请参见Spring Boot文档和ConfigFileApplicationListener.load()方法的源代码。
Lu55

18

您可以@TestPropertySource用来加载不同的属性/ 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"
        }
)

3
我尝试使用此批注,但在测试中它仍在查找application.yml而不是我指定的注解。
ttt

9

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

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

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

选项2:使用特定application-test.yml配置文件的属性:在您的src/test/resources/文件夹中创建“说” ,然后:

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

    @SpringBootTest(classes = Application.class)
    @ActiveProfiles("test")
    public class MyIntTest {
    
  • 或者spring.profiles.active@SpringBootTest注释中设置属性值:

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

这不但可以用@SpringBootTest,但用@JsonTest@JdbcTests@DataJpaTest等片测试注释为好。

而且,您可以根据需要设置任意多个配置文件(spring.profiles.active=dev,hsqldb)-有关配置文件的详细信息,请参阅。


5

查看此内容:使用YAML的Spring @PropertySource

我认为第三个答案就是您要寻找的,即有一个单独的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;

}

5

Spring-boot框架允许我们提供YAML文件来代替.properties文件,这很方便。属性文件中的密钥可以YAML格式在资源文件夹中的application.yml文件中提供,并且spring-boot将自动采用请记住,yaml格式必须保持空格正确才能正确读取该值。

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

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

如果要指定application-test.yml.yml并在.yml中提供弹簧测试配置文件,则可以使用@ActiveProfiles('test')批注指示spring从指定的application-test.yml中获取配置。

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

如果您使用的是JUnit 5,则不需要其他注释,因为@SpringBootTest已包含springrunner注释。保留单独的主ApplicationTest.class使我们能够为测试提供单独的配置类,并且可以通过从测试主类的组件扫描中排除默认配置Bean来防止加载默认配置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

使用一个简单的工作配置

@TestPropertySource和属性

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


    @Test

    public void someTest() {
    }
}

2

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

@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

2

这可能被认为是选项之一。现在,如果您想加载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;
    }
}

0

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

@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注释,否则我们可以使用config属性类。例如

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

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

0

Lu55选项1如何...

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

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

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

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

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

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

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

可选:安排项目浏览器视图的文件夹顺序。轻按“订单和导出”选项卡上的标记,然后将{projectname} / src / test / recources移至底部。申请并关闭

!!!清理项目!
Eclipse->项目->清洁...

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.