Spring @PropertySource utilisant YAML

Spring Boot nous permet de remplacer nos fichiers application.properties par des équivalents YAML. Cependant, je semble avoir un problème avec mes tests. Si TestConfiguration mon TestConfiguration (une simple configuration Java), il attend un fichier de propriétés.

Par exemple, cela ne fonctionne pas: @PropertySource(value = "classpath:application-test.yml")

Si je l’ai dans mon fichier YAML:

 db: url: jdbc:oracle:thin:@pathToMyDb username: someUser password: fakePassword 

Et je tirerais parti de ces valeurs avec quelque chose comme ceci:

 @Value("${db.username}") Ssortingng username 

Cependant, je finis avec et erreur comme ça:

 Could not resolve placeholder 'db.username' in ssortingng value "${db.username}" 

Comment puis-je également tirer parti des bienfaits de YAML dans mes tests?

Spring-boot a une aide pour cela, il suffit d’append

 @ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) 

en haut de vos classes de test ou une super-classe de test abstraite.

Comme il a été mentionné, @PropertySource ne charge pas le fichier yaml. Pour contourner le problème, chargez le fichier vous-même et ajoutez les propriétés chargées à l’ Environment .

Implémentation ApplicationContextInitializer :

 public class YamlFileApplicationContextInitializer implements ApplicationContextInitializer { @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); } } } 

Ajoutez votre initialiseur à votre test:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class) public class SimpleTest { @Test public test(){ // test your properties } } 

@PropertySource ne supporte que les fichiers de propriétés (c’est une limitation de Spring, pas Boot elle-même). N’hésitez pas à ouvrir un ticket de demande de fonctionnalité dans JIRA .

L’approche pour charger les propriétés de l’igname, IMHO peut être faite de deux manières:

une. Vous pouvez placer la configuration dans un emplacement standard – application.yml dans la racine du chemin de classe – généralement src/main/resources et cette propriété yaml devrait être automatiquement chargée par Spring boot avec le nom de chemin aplati que vous avez mentionné.

b. La seconde approche est un peu plus étendue, définissant essentiellement une classe pour contenir vos propriétés de cette manière:

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

Donc essentiellement cela dit que charger le fichier yaml et remplir la classe DbProperties basée sur l’élément racine de “db”.

Maintenant, pour l’utiliser dans n’importe quelle classe, vous devrez le faire:

 @EnableConfigurationProperties(DbProperties.class) public class PropertiesUsingService { @Autowired private DbProperties dbProperties; } 

Chacune de ces approches devrait fonctionner pour vous de manière propre en utilisant Spring-boot.

Depuis Spring Boot 1.4, vous pouvez utiliser la nouvelle annotation @SpringBootTest pour y parvenir plus facilement (et pour simplifier la configuration de vos tests d’intégration en général) en amorçant vos tests d’intégration à l’aide de la prise en charge de Spring Boot.

Détails sur le blog de spring .

Autant que je sache, cela signifie que vous obtenez tous les avantages de la qualité de configuration externalisée de Spring Boot, tout comme dans votre code de production, y compris la saisie automatique de la configuration YAML dans le classpath.

Par défaut, cette annotation sera

… d’abord essayer de charger @Configuration partir de n’importe quelle classe interne, et si cela échoue, il recherchera votre classe @SpringBootApplication principale.

mais vous pouvez spécifier d’autres classes de configuration si nécessaire.

Pour ce cas particulier, vous pouvez combiner @SpringBootTest avec @ActiveProfiles( "test" ) et Spring récupérera votre configuration YAML, à condition qu’elle respecte les normes de dénomination de démarrage normales ( application-test.yml ).

 @RunWith( SpringRunner.class ) @SpringBootTest @ActiveProfiles( "test" ) public class SpringBootITest { @Value("${db.username}") private Ssortingng username; @Autowired private MyBean myBean; ... } 

Remarque: SpringRunner.class est le nouveau nom de SpringJUnit4ClassRunner.class

Une autre option consiste à définir le spring.config.location via @TestPropertySource :

 @TestPropertySource(properties = { "spring.config.location = classpath:" } 

J’ai trouvé une solution en utilisant @ActiveProfiles("test") et en ajoutant un fichier application-test.yml à src / test / resources.

Cela a fini par ressembler à ceci:

 @SpringApplicationConfiguration(classes = Application.class, initializers = ConfigFileApplicationContextInitializer.class) @ActiveProfiles("test") public abstract class AbstractIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests { } 

Le fichier application-test.yml ne contient que les propriétés que je veux remplacer depuis application.yml (que vous pouvez trouver dans src / main / resources).

@PropertySource peut être configuré par argument de factory . Vous pouvez donc faire quelque chose comme:

 @PropertySource(value = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) 

YamlPropertyLoaderFactory est votre chargeur de propriété personnalisé:

 public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory { @Override public PropertySource createPropertySource(Ssortingng name, EncodedResource resource) throws IOException { if (resource == null){ return super.createPropertySource(name, resource); } return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null); } } 

Inspiré par https://stackoverflow.com/a/45882447/4527110

c’est parce que vous n’avez pas configuré snakeyml. botte à ressort avec fonction @EnableAutoConfiguration. il y a aussi la configuration de snakeyml quand vous appelez cette annotation.

c’est mon chemin:

 @Configuration @EnableAutoConfiguration public class AppContextTest { } 

voici mon test:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration( classes = { AppContextTest.class, JaxbConfiguration.class, } ) public class JaxbTest { //tests are ommited } 

J’avais besoin de lire certaines propriétés dans mon code et cela fonctionne avec 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); } 

Chargement d’un fichier yml personnalisé avec la configuration de plusieurs profils dans Spring Boot.

1) Ajoutez le bean de propriété avec SpringBootApplication comme suit

 @SpringBootApplication @ComponentScan({"com.example.as.*"}) public class TestApplication { public static void main(Ssortingng[] 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(Ssortingng 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) Configurez l’object Java pojo comme suit

 @Component @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(Include.NON_NULL) @ConfigurationProperties(prefix = "test-service") public class TestConfig { @JsonProperty("id") private Ssortingng id; @JsonProperty("name") private Ssortingng name; public Ssortingng getId() { return id; } public void setId(Ssortingng id) { this.id = id; } public Ssortingng getName() { return name; } public void setName(Ssortingng name) { this.name = name; } } 

3) Créez le yml personnalisé (et placez-le sous le chemin de ressource comme suit, nom du fichier YML: test-service-config.yml

Par exemple Config dans le fichier 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 

Améliorer la réponse de Mateusz Balbus .

Classe YamlFileApplicationContextInitializer modifiée où l’emplacement YAML est défini par classe de test. Cela ne fonctionne pas par test, malheureusement.

 public abstract class YamlFileApplicationContextInitializer implements ApplicationContextInitializer { /*** * Return location of a YAML file, eg: classpath:file.yml * * @return YAML file location */ protected abstract Ssortingng getResourceLocation(); @Override public void initialize(ConfigurableApplicationContext applicationContext) { try { Resource resource = applicationContext.getResource(getResourceLocation()); YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader(); PropertySource yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null); applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties); } catch (IOException e) { throw new RuntimeException(e); } } } 

Usage:

Créez la sous-classe de YamlFileApplicationContextInitializer avec la méthode getResourceLocation() définie et ajoutez cette sous-classe à l’annotation @SpringApplicationConfiguration .

Je pense que le plus simple est de faire de la classe de test elle-même une sous-classe spécifique comme dans l’exemple suivant.

 @RunWith(SpringRunner.class) @SpringApplicationConfiguration(classes = Application.class, initializers = SimpleTest.class) public class SimpleTest extends YamlFileApplicationContextInitializer { @Override protected Ssortingng getResourceLocation() { return "classpath:test_specific.yml"; } @Test public test(){ // test your properties } }