Spring @PropertySource using YAML

Spring Boot pozwala nam zastąpić naszą aplikację.pliki właściwości z odpowiednikami YAML. Jednak wydaje mi się, że mam problem z moimi testami. Jeśli dodam adnotację do mojego TestConfiguration (prostej konfiguracji Javy), oczekuje on pliku właściwości.

Na przykład to nie działa: @PropertySource(value = "classpath:application-test.yml")

Jeśli mam to w moim pliku YAML:

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

I wykorzystałbym te wartości czymś takim:

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

Jednak kończę z i błąd tak:

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

Jak mogę wykorzystać dobroć YAML również w moich testach?

Author: checketts, 2014-01-21

17 answers

Spring-boot ma do tego helpera, wystarczy dodać

@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)

Na górze Twoich klas testowych lub abstrakcyjnej klasy testowej.

Edit: napisałem tę odpowiedź pięć lat temu. Nie działa z najnowszymi wersjami Spring Boot. To jest to, co robię teraz (proszę przetłumaczyć Kotlina na Javę, jeśli to konieczne):

@TestPropertySource(locations=["classpath:application.yml"])
@ContextConfiguration(
        initializers=[ConfigFileApplicationContextInitializer::class]
)

Dodaje się do góry, następnie

    @Configuration
    open class TestConfig {

        @Bean
        open fun propertiesResolver(): PropertySourcesPlaceholderConfigurer {
            return PropertySourcesPlaceholderConfigurer()
        }
    }

Do kontekstu.

 61
Author: Ola Sundell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-25 13:45:22

Jak wspomniano @PropertySource nie wczytuje pliku yaml. Jako obejście Załaduj plik samodzielnie i dodaj załadowane właściwości do 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);
    }
  }
}

Dodaj swój inicjalizator do testu:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class)
public class SimpleTest {
  @Test
  public test(){
    // test your properties
  }
}
 60
Author: Mateusz Balbus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 01:38:46

@PropertySource można skonfigurować za pomocą argumentu factory. Więc możesz zrobić coś w stylu:

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

Gdzie YamlPropertyLoaderFactory jest Twoim niestandardowym loaderem właściwości:

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);
    }
}

Inspired by https://stackoverflow.com/a/45882447/4527110

 36
Author: Сергей Варюхин,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-18 02:28:27

@PropertySource obsługuje tylko pliki właściwości (jest to ograniczenie od Springa, a nie sam Boot). Możesz otworzyć zgłoszenie żądania funkcji w JIRA .

 28
Author: Dave Syer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 07:35:11

Inną opcją jest ustawienie spring.config.location przez @TestPropertySource:

@TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }
 24
Author: Doc Davluz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-26 18:42:20

Od wersji Spring Boot 1.4, możesz użyć nowej adnotacji @SpringBootTest, aby to łatwiej osiągnąć (i ogólnie uprościć konfigurację testów integracyjnych)poprzez bootstrapowanie testów integracyjnych przy użyciu obsługi Spring Boot.

Szczegóły na wiosennym blogu.

Z tego co wiem, oznacza to, że otrzymujesz wszystkie zalety Spring Boot ' s externalized Config goodness tak jak w Twoim kodzie produkcyjnym, w tym automatyczne pobieranie konfiguracji YAML z classpath.

Domyślnie ta adnotacja będzie

... pierwsza próba załadowania @Configuration z dowolnej klasy wewnętrznej, a jeśli to się nie powiedzie, będzie szukać podstawowej @SpringBootApplication klasy.

Ale w razie potrzeby możesz określić inne klasy konfiguracji.

W tym konkretnym przypadku, możesz połączyć @SpringBootTest z @ActiveProfiles( "test" ) i Spring odbierze konfigurację YAML, pod warunkiem, że będzie ona zgodna z normalnymi standardami nazw ROZRUCHOWYCH (np. application-test.yml).

@RunWith( SpringRunner.class )
@SpringBootTest
@ActiveProfiles( "test" )
public class SpringBootITest {

    @Value("${db.username}")
    private String username;

    @Autowired
    private MyBean myBean;

    ...

}

Uwaga: SpringRunner.class jest nowa nazwa dla SpringJUnit4ClassRunner.class

 21
Author: moogpwns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-08 17:39:09

Podejście do ładowania właściwości yaml, IMHO można zrobić na dwa sposoby:

A. Możesz umieścić konfigurację w standardowej lokalizacji - application.yml w katalogu głównym classpath - zazwyczaj src/main/resources i ta właściwość yaml powinna zostać automatycznie załadowana przez Spring boot z nazwą spłaszczonej ścieżki, o której wspomniałeś.

B. drugie podejście jest nieco bardziej rozbudowane, zasadniczo zdefiniuj klasę, która przechowuje Twoje właściwości w ten sposób:

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

Więc zasadniczo mówi się, że Załaduj plik yaml i uzupełnij klasę DbProperties w oparciu o główny element "db".

Teraz, aby użyć go w dowolnej klasie, musisz to zrobić:

@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {

    @Autowired private DbProperties dbProperties;

}

Każda z tych metod powinna działać dla Ciebie czysto przy użyciu Spring-boot.

 10
Author: Biju Kunjummen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 01:36:50

Znalazłem obejście używając @ActiveProfiles("test") i dodając Test aplikacji.plik yml do src / test/resources.

Skończyło się tak:

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

}

Aplikacja pliku-test.yml zawiera tylko właściwości, które chcę zastąpić z aplikacji.yml (który można znaleźć w src / main / resources).

 3
Author: Poly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-16 15:58:15

To dlatego, że nie skonfigurowałeś snakeyml. sprężynowe buty są wyposażone w funkcję konfiguracji @EnableAutoConfiguration. jest też konfiguracja snakeyml, gdy wywołujesz tę adnotację..

This is my way:

@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}

Oto mój test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
        classes = {
                AppContextTest.class,
                JaxbConfiguration.class,
        }
)

public class JaxbTest {
//tests are ommited
}
 1
Author: user2582794,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-12 07:33:30

Musiałem wczytać kilka właściwości do mojego kodu i działa to Z 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);
}
 0
Author: U.V.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-10 18:56:12

Ładowanie niestandardowego pliku yml z konfiguracją wielu profili podczas wiosennego rozruchu.

1) Dodaj właściwość bean z SpringBootApplication Uruchom się w następujący sposób

@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) Konfiguracja obiektu pojo Java w następujący sposób

@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) Utwórz niestandardowy yml (i umieść go pod ścieżką zasobów w następujący sposób, Nazwa pliku YML: test-service-config.yml

Np. Config w pliku 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
 0
Author: Arunachalam Govindasamy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 21:56:57

Byłem w szczególnej sytuacji, w której nie mogłem załadować klasy @ConfigurationProperties z powodu niestandardowego nazewnictwa właściwości plików. Na koniec działa tylko (dzięki @ 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();

    }

}
 0
Author: aldebaran-ms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-11 15:06:21
<dependency>
  <groupId>com.github.yingzhuo</groupId>
  <artifactId>spring-boot-stater-env</artifactId>
  <version>0.0.3</version>
</dependency>
Zapraszam do korzystania z mojej biblioteki. Teraz yaml, toml, hocon jest obsługiwana.

Źródło: github.com

 0
Author: Zhuo YING,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-06 03:00:25

Nie jest to odpowiedź na pierwotne pytanie, ale alternatywne rozwiązanie dla potrzeby posiadania innej konfiguracji w teście...

Zamiast @PropertySource możesz użyć -Dspring.config.additional-location=classpath:application-tests.yml.

Należy pamiętać, że przyrostek tests nie oznacza profilu...

W tym jednym pliku YAML można określić wiele profili, które mogą dziedziczyć po sobie, Czytaj więcej tutaj - właściwość rozwiązująca dla wielu profili sprężynowych (konfiguracja yaml)

Wtedy można określić w twój test, że aktywne profile (za pomocą @ActiveProfiles("profile1,profile2")) są profile1,profile2 Gdzie profile2 po prostu nadpisuje (niektóre, nie trzeba nadpisywać wszystkich) właściwości z profile1.

 0
Author: Betlista,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-04 12:56:29

Próbowałem wszystkich wymienionych pytań, ale wszystkie nie działają na moje zadanie: używanie konkretnego pliku yaml do jakiegoś testu jednostkowego. W moim przypadku działa to tak:

@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);
    }

}
 0
Author: FedorM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 14:28:29

Miałem podobny problem. Używam SpringBoot 2.4.1. Jeśli napotkasz podobny problem, tzn. nie możesz załadować plików yml, spróbuj dodać adnotację na poziomie klasy w swoim teście.

@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);
    }
}

ConfigDataApplicationContextInitializer z import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; jest Tym, który "pomaga" przetłumaczyć yml pliki.

Jestem w stanie pomyślnie przeprowadzić test.
 0
Author: Ishak Antony Darmawan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-01 07:10:10

Nie ma potrzeby dodawania takich jak YamlPropertyLoaderFactory lub YamlFileApplicationContextInitializer. Powinieneś zmienić swój pomysł. zupełnie jak wspólny projekt wiosenny. Nie używam Javy config. Tylko *.xml

Wykonaj następujące kroki:

Wystarczy dodać applicationContext.XML like

<?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>

Następnie dodaj

@ImportResource({"classpath:applicationContext.xml"})

Do twojego ApplicationMainClass.

To może pomóc zeskanować aplikację-test.yml

db:
  url: jdbc:oracle:thin:@pathToMyDb
  username: someUser
  password: fakePassword
 -6
Author: Forest10,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-24 09:29:37