Spring Boot允许我们用YAML等价物替换我们的application.properties文件。但是我的测试似乎遇到了麻烦。如果我注释我的TestConfiguration
(一个简单的Java配置),它会期待一个属性文件。
例如,这不起作用:
@PropertySource(value = "classpath:application-test.yml")
如果我在YAML文件中有这个:
db:
url: jdbc:oracle:thin:@pathToMyDb
username: someUser
password: fakePassword
我会用这样的东西来利用这些价值观:
@Value("${db.username}") String username
然而,我最终得到了错误:
Could not resolve placeholder 'db.username' in string value "${db.username}"
我如何在测试中利用YAML的优点?
答案 0 :(得分:47)
如前所述,@PropertySource
并未加载yaml文件。解决方法是自行加载文件并将加载的属性添加到Environment
。
实施ApplicationContextInitializer
:
public class YamlFileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
Resource resource = applicationContext.getResource("classpath:file.yml");
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
PropertySource<?> yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null);
applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
将初始化程序添加到测试中:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class)
public class SimpleTest {
@Test
public test(){
// test your properties
}
}
答案 1 :(得分:40)
Spring-boot有一个帮手,只需添加
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
位于测试类的顶部或抽象测试超类。
答案 2 :(得分:25)
@PropertySource
仅支持属性文件(这是Spring的限制,而不是Boot本身)。随意打开功能请求票in JIRA。
答案 3 :(得分:17)
从Spring Boot 1.4开始,您可以使用新的@SpringBootTest
注释通过使用Spring Boot支持引导集成测试来更轻松地实现这一目标(并简化集成测试设置)。
Spring Blog的详细信息。
据我所知,这意味着您可以像生产代码一样获得Spring Boot externalized config goodness的所有好处,包括从类路径中自动获取YAML配置。
默认情况下,此注释将
...首先尝试从任何内部类加载
@Configuration
,如果失败,它将搜索您的主要@SpringBootApplication
类。
但您可以根据需要指定其他配置类。
对于这种特殊情况,您可以将@SpringBootTest
与@ActiveProfiles( "test" )
结合使用,如果Spring遵循正常的引导命名标准(即application-test.yml
),Spring将选择您的YAML配置。
@RunWith( SpringRunner.class )
@SpringBootTest
@ActiveProfiles( "test" )
public class SpringBootITest {
@Value("${db.username}")
private String username;
@Autowired
private MyBean myBean;
...
}
注意:SpringRunner.class
是SpringJUnit4ClassRunner.class
答案 4 :(得分:13)
@PropertySource
可以通过factory
参数进行配置。因此,您可以执行以下操作:
@PropertySource(value = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class)
YamlPropertyLoaderFactory
是您的自定义属性加载器:
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null){
return super.createPropertySource(name, resource);
}
return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null);
}
}
的启发
答案 5 :(得分:10)
加载yaml属性的方法,恕我直言可以通过两种方式完成:
一个。您可以将配置放在类路径根目录中的标准位置 - application.yml
- 通常为src/main/resources
,并且此yaml属性应该由Spring引导自动加载,并使用您提到的扁平路径名。
湾第二种方法更广泛,基本上定义一个类以这种方式保存您的属性:
@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties {
private String url;
private String username;
private String password;
...
}
所以基本上这就是说加载yaml文件并根据“db”的根元素填充DbProperties类。
现在要在任何课程中使用它,你必须这样做:
@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {
@Autowired private DbProperties dbProperties;
}
使用Spring-boot,这些方法中的任何一个都应该干净利落。
答案 6 :(得分:9)
另一个选项是将spring.config.location
设置为@TestPropertySource
:
@TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }
答案 7 :(得分:3)
我找到了一种解决方法,使用@ActiveProfiles("test")
并将application-test.yml文件添加到src / test / resources。
最终看起来像这样:
@SpringApplicationConfiguration(classes = Application.class, initializers = ConfigFileApplicationContextInitializer.class)
@ActiveProfiles("test")
public abstract class AbstractIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests {
}
文件application-test.yml只包含我想要从application.yml覆盖的属性(可以在src / main / resources中找到)。
答案 8 :(得分:1)
从 Spring Boot 2.4.0 开始,您可以使用 ConfigDataApplicationContextInitializer 如下:
@SpringJUnitConfig(
classes = { UserAccountPropertiesTest.TestConfig.class },
initializers = { ConfigDataApplicationContextInitializer.class }
)
class UserAccountPropertiesTest {
@Configuration
@EnableConfigurationProperties(UserAccountProperties.class)
static class TestConfig { }
@Autowired
UserAccountProperties userAccountProperties;
@Test
void getAccessTokenExpireIn() {
assertThat(userAccountProperties.getAccessTokenExpireIn()).isEqualTo(120);
}
@Test
void getRefreshTokenExpireIn() {
assertThat(userAccountProperties.getRefreshTokenExpireIn()).isEqualTo(604800);
}
}
另见:https://www.baeldung.com/spring-boot-testing-configurationproperties#YAML-binding
答案 9 :(得分:0)
项目演示网址:https://github.com/Forest10/spring-boot-family/tree/spring-boot-with-yml
我在我的 prod 环境中运行这个答案!!!所以如果你反对这个答案。请先测试!!!
不需要像 YamlPropertyLoaderFactory 或 YamlFileApplicationContextInitializer 那样添加。你应该转换你的想法
请按照以下步骤操作:
只需添加 applicationContext.xml 就像
@ImportResource({"classpath:applicationContext.xml"})
到您的 ApplicationMainClass。
你的 applicationContext.xml 应该这样写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
default-autowire="byName"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:property-placeholder location="classpath*:*.yml"/>
</beans>
这可以帮助扫描您的 application-test.yml
db:
url: jdbc:oracle:thin:@pathToMyDb
username: someUser
password: fakePassword
答案 10 :(得分:0)
我已经尝试了所有列出的问题,但是它们都不适合我的任务:使用特定的yaml文件进行某些单元测试。 就我而言,它是这样的:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = {ConfigFileApplicationContextInitializer.class})
@TestPropertySource(properties = {"spring.config.location=file:../path/to/specific/config/application.yml"})
public class SomeTest {
@Value("${my.property.value:#{null}}")
private String value;
@Test
public void test() {
System.out.println("value = " + value);
}
}
答案 11 :(得分:0)
这不是对原始问题的答案,而是需要在测试中具有不同配置的替代解决方案...
您可以使用@PropertySource
代替-Dspring.config.additional-location=classpath:application-tests.yml
。
请注意,后缀tests
并不意味着个人资料...
由于一个YAML文件可以指定多个配置文件,而这些配置文件可以相互继承,请在此处详细了解-Property resolving for multiple Spring profiles (yaml configuration)
然后,您可以在测试中指定(使用@ActiveProfiles("profile1,profile2")
的活动配置文件是profile1,profile2
,其中profile2
将仅覆盖(某些不需要覆盖所有属性)属性来自profile1
。
答案 12 :(得分:0)
<dependency>
<groupId>com.github.yingzhuo</groupId>
<artifactId>spring-boot-stater-env</artifactId>
<version>0.0.3</version>
</dependency>
欢迎使用我的图书馆。现在支持 yaml , toml , hocon
来源:github.com
答案 13 :(得分:0)
在特殊情况下,由于自定义文件属性的命名,我无法加载@ConfigurationProperties类。最后,唯一有效的方法是(感谢@Mateusz Balbus):
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {MyTest.ContextConfiguration.class})
public class MyTest {
@TestConfiguration
public static class ContextConfiguration {
@Autowired
ApplicationContext applicationContext;
@Bean
public ConfigurationPropertiesBean myConfigurationPropertiesBean() throws IOException {
Resource resource = applicationContext.getResource("classpath:my-properties-file.yml");
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
List<PropertySource<?>> loadedSources = sourceLoader.load("yamlTestProperties", resource);
PropertySource<?> yamlTestProperties = loadedSources.get(0);
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment)applicationContext.getEnvironment();
configurableEnvironment.getPropertySources().addFirst(yamlTestProperties);
Binder binder = Binder.get(applicationContext.getEnvironment());
ConfigurationPropertiesBean configurationPropertiesBean = binder.bind("my-properties-file-prefix", Bindable.of(ConfigurationPropertiesBean.class)).get();
return configurationPropertiesBean;
}
}
@Autowired
ConfigurationPropertiesBean configurationPropertiesBean;
@Test
public void test() {
configurationPropertiesBean.getMyProperty();
}
}
答案 14 :(得分:0)
您可以通过在@PropertySource
属性中提供一个类来配置factory
来加载YAML文件。我实现了一个版本,该版本也可以考虑您部署的活动配置文件:)。
答案 15 :(得分:0)
无需添加YamlPropertyLoaderFactory或YamlFileApplicationContextInitializer之类的内容。 您应该改变主意。就像普通的春季项目一样。你知道,不使用Java配置。
仅* .xml
只需添加
之类的applicationContext.xml<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-autowire="byName">
<context:property-placeholder location="classpath*:*.yml"/>
</beans>
然后添加
@ImportResource({"classpath:application*.xml"})
到您的ApplicationMainClass
一切正常!
答案 16 :(得分:0)
在Spring Boot中加载带有多个配置文件配置的自定义yml文件。
1)使用SpringBootApplication启动添加属性bean,如下所示
@SpringBootApplication
@ComponentScan({"com.example.as.*"})
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Bean
@Profile("dev")
public PropertySourcesPlaceholderConfigurer propertiesStage() {
return properties("dev");
}
@Bean
@Profile("stage")
public PropertySourcesPlaceholderConfigurer propertiesDev() {
return properties("stage");
}
@Bean
@Profile("default")
public PropertySourcesPlaceholderConfigurer propertiesDefault() {
return properties("default");
}
/**
* Update custom specific yml file with profile configuration.
* @param profile
* @return
*/
public static PropertySourcesPlaceholderConfigurer properties(String profile) {
PropertySourcesPlaceholderConfigurer propertyConfig = null;
YamlPropertiesFactoryBean yaml = null;
propertyConfig = new PropertySourcesPlaceholderConfigurer();
yaml = new YamlPropertiesFactoryBean();
yaml.setDocumentMatchers(new SpringProfileDocumentMatcher(profile));// load profile filter.
yaml.setResources(new ClassPathResource("env_config/test-service-config.yml"));
propertyConfig.setProperties(yaml.getObject());
return propertyConfig;
}
}
2)按如下方式配置Java pojo对象
@Component
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
@ConfigurationProperties(prefix = "test-service")
public class TestConfig {
@JsonProperty("id")
private String id;
@JsonProperty("name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3)创建自定义yml(并将其放在资源路径下,如下所示, YML文件名:test-service-config.yml
例如,在yml文件中配置。
test-service:
id: default_id
name: Default application config
---
spring:
profiles: dev
test-service:
id: dev_id
name: dev application config
---
spring:
profiles: stage
test-service:
id: stage_id
name: stage application config
答案 17 :(得分:0)
我需要在我的代码中读取一些属性,这适用于spring-boot 1.3.0.RELEASE
@Autowired
private ConfigurableListableBeanFactory beanFactory;
// access a properties.yml file like properties
@Bean
public PropertySource properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("properties.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
// properties need to be processed by beanfactory to be accessible after
propertySourcesPlaceholderConfigurer.postProcessBeanFactory(beanFactory);
return propertySourcesPlaceholderConfigurer.getAppliedPropertySources().get(PropertySourcesPlaceholderConfigurer.LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME);
}
答案 18 :(得分:0)
这是因为你没有配置snakeyml。 spring boot附带@EnableAutoConfiguration功能。 当你调用这个注释时,也有snakeyml配置..
这是我的方式:
@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}
这是我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
classes = {
AppContextTest.class,
JaxbConfiguration.class,
}
)
public class JaxbTest {
//tests are ommited
}