web-dev-qa-db-fra.com

Spring Boot: configuration des propriétés personnalisées et tests

J'utilise Spring Boot 2.0 avec le fichier de propriétés application.yml par défaut. Je voudrais le scinder pour séparer les fichiers de propriétés car il devient énorme.
J'aimerais également écrire des tests pour vérifier l'exactitude des propriétés: valeurs qui seront présentées dans le contexte de l'application de production (et non le test).

Voici mon fichier de propriétés: src/main/resources/config/custom.yml

my-property:
  value: 'test'

Classe de propriété:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Data
@Configuration
@ConfigurationProperties(prefix = "my-property")
@PropertySource("classpath:config/custom.yml")
public class MyProperty {

  private String value;
}

Tester:

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@EnableConfigurationProperties
public class MyPropertyTest {

  @Autowired
  private MyProperty property;

  @Test
  public void test() {
    assertEquals("test", property.getValue());
  }

}

Mais le test échoue avec une erreur:

Java.lang.AssertionError: 
Expected :test
Actual   :null

De plus, je vois que la valeur de la propriété est null lors de l'exécution de l'application en l'imprimant dans ApplicationRunner.
Lorsque j’utilisais application.yml pour toutes les propriétés, la configuration était identique. 

Comment mettre la configuration correcte pour les propriétés et les tests pour le faire fonctionner?
Lien vers Github repo

4
Bullet-tooth

J'ai enfin trouvé le bon moyen d'avoir des propriétés personnalisées dans mon application. 

Le problème est que Spring ne prend pas en charge les fichiers yaml en tant que @PropertySource ( lien vers issue ). Et voici une solution de contournement pour traiter celle décrite dans documentation de printemps .
Donc, pour pouvoir charger les propriétés à partir de fichiers yaml, il vous faut:
* Pour implémenter EnvironmentPostProcessor
* Pour l'enregistrer dans spring.factories 

Veuillez visiter ce github repo pour un exemple complet. 

Merci également pour votre soutien, les gars! 

3
Bullet-tooth

@TestPropertySource peut résoudre votre problème.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@TestPropertySource(locations="classpath:test.properties")
public class MyPropertyTest {

@Autowired
private MyProperty property;

@Test
public void test() {
   assertEquals("test", property.getValue());
}
}

J'espère que ça aide.

2
Antariksh

Je suis un peu en retard à la fête, mais cela pourrait aussi aider. La solution proposée comme réponse est la meilleure approche à ce jour, mais voici une alternative que j'ai utilisée

Utilisez les profils et modifiez le bean PropertySoucesPlaceHolderConfiguration pour charger les fichiers de propriétés nécessaires en fonction des profils. Il charge le fichier application.properties par défaut, mais les autres fichiers de propriétés -oauth_DEV et oauth_QA sont chargés en fonction des profils définis.

@Bean
    public PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurerconfigurer() {

        System.out.println("Inside Placeholder bean");
        PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer();
        ClassPathResource cls1=  new ClassPathResource("application.properties");
         ClassPathResource cls2 = null;

        Map<String, Object> propMap = ((ConfigurableEnvironment) ctx.getEnvironment()).getSystemProperties();
        for(Map.Entry<String, Object> entrySet: propMap.entrySet()) {
            System.out.println("Map.Key:"+entrySet.getKey()+"  Map.valiue:"+entrySet.getValue());
        }

        List<String> profiles=  Arrays.asList(ctx.getEnvironment().getActiveProfiles());
        if(profiles == null || profiles.isEmpty()) {
            if(!propMap.containsKey("spring.profiles.active")) {
                cls2 = new ClassPathResource("oauth-default.properties");
            } else {
                cls2 = new ClassPathResource("oauth-"+propMap.get("spring.profiles.active")+".properties");
            }
        }else {
            for(String profile:profiles) {
                if(profile.equalsIgnoreCase("DEV")) {
                    cls2 =  new ClassPathResource("oauth-DEV.properties");
                }else if(profile.equalsIgnoreCase("QA")) {
                    cls2 =  new ClassPathResource("oauth-QA.properties");
                }else if (profile.equalsIgnoreCase("UAT")) {
                    cls2 =  new ClassPathResource("oauth-UAT.properties");
                }else if(profile.equalsIgnoreCase("PROD")){
                    cls2 =  new ClassPathResource("oauth-PROD.properties");
                }else {
                    cls2 = new ClassPathResource("oauth-default.properties");
                }
            }
        }

        cfg.setLocations(cls1,cls2);
        //cfg.setPlaceholderPrefix("#{");
        return cfg;
    }

Créez ensuite un autre bean qui lit les propriétés en fonction du préfixe "security.oauth2.client".

@Configuration
@ConfigurationProperties(prefix="security.oauth2.client")
public class OauthSecurityConfigurationDto {

    private String clientId;
    private String clientSecret;
    private String scope;
    private String accessTokenUri;
    private String userAuthorizationUri;
    private String grantType;
    private String resourceIds;
    private String registeredRedirectUri;
    private String preEstablishedRedirectUri;
    private String useCurrentUri;
    private String userInfoUri;
    public String getClientId() {
        return clientId;
    }
    public void setClientId(String clientId) {
        this.clientId = clientId;
    }
    public String getClientSecret() {
        return clientSecret;
    }
    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    public String getAccessTokenUri() {
        return accessTokenUri;
    }
    public void setAccessTokenUri(String accessTokenUri) {
        this.accessTokenUri = accessTokenUri;
    }
    public String getUserAuthorizationUri() {
        return userAuthorizationUri;
    }
    public void setUserAuthorizationUri(String userAuthorizationUri) {
        this.userAuthorizationUri = userAuthorizationUri;
    }
    public String getGrantType() {
        return grantType;
    }
    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }
    public String getResourceIds() {
        return resourceIds;
    }
    public void setResourceIds(String resourceIds) {
        this.resourceIds = resourceIds;
    }
    public String getRegisteredRedirectUri() {
        return registeredRedirectUri;
    }
    public void setRegisteredRedirectUri(String registeredRedirectUri) {
        this.registeredRedirectUri = registeredRedirectUri;
    }
    public String getPreEstablishedRedirectUri() {
        return preEstablishedRedirectUri;
    }
    public void setPreEstablishedRedirectUri(String preEstablishedRedirectUri) {
        this.preEstablishedRedirectUri = preEstablishedRedirectUri;
    }
    public String getUseCurrentUri() {
        return useCurrentUri;
    }
    public void setUseCurrentUri(String useCurrentUri) {
        this.useCurrentUri = useCurrentUri;
    }
    public String getUserInfoUri() {
        return userInfoUri;
    }
    public void setUserInfoUri(String userInfoUri) {
        this.userInfoUri = userInfoUri;
    }


}

Rappelez-vous que les setters sont importants car la ConfigurationProperties charge les valeurs dans les propriétés de la classe uniquement lorsque des getters et des setters sont définis.

Nous pouvons maintenant autoriser la dépendance si nécessaire et utiliser la propriété.

1
Joey587

S'il s'agit de votre code exact, cela signifie que vous lisez votre propriété à partir d'un fichier de propriété incorrect.

remplacez votre ressource de propriété par cette ligne.

@PropertySource("classpath:config/services.yml")
0
Ravat Tailor