在 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-webflux 中加载配置?
spring - @ContextConfiguration 无法在 src/test/resources 中加载配置文件