[FIXED] How to test Externalized Configuration reading from yaml

Issue

This is my first time working with Externalized Configuration and yaml.

I created a yaml where I use the class name as KEY, and the field name as VALUE

YAML:

# test placeholders
project:
  test:
    service:
      computator:
        # exclude field from beeing randomly valorized
        population:
          exclude:
            InputClass: 'myDate'
            AnotherClass: 'myName'

ExcludePopulationProperties:

@Data
@Component
@ConfigurationProperties(prefix = "project")
public class ExcludePopulationProperties {

    private Test test;

    @Data
    public static class Test {
        private Service service;
    }

    @Data
    public static class Service {
        private Computator computator;
    }

    @Data
    public static class Computator {
        private Population population;
    }

    @Data
    public static class Population {
        private Map<String, String> exclude;
    }

}

Test with JUnit 5:

@ContextConfiguration(classes = { ExcludePopulationProperties.class })
@ExtendWith(SpringExtension.class)
class YamlTest {

    @Autowired
    private ExcludePopulationProperties excludePopulationProperties;

    @Test
    void testExternalConfiguration() {
        Map<String, String> map = excludePopulationProperties.getTest().getService().getComputator().getPopulation().getExclude();
        assertNotNull(map);
    }

The problem is that I have a NullPointerException because test is null enter image description here

So I’m not sure what is wrong here, I was expecting that the map was correctly populated.

I also tried to add

@TestPropertySource(properties = { "spring.config.location=classpath:application-_test.yaml" })

on the YamlTest

Solution

With these little changes, now I’m able to test the property value from YAML file.

I improved the yaml a little bit:

# test placeholders
project:
  test:
    service:
      computator:
        # exclude field from beeing randomly valorized
        population:
          exclude:
            InputClass: 
               - 'myDate'
            AnotherClass: 
               - 'myName'

so now the ExcludePopulationProperties have a Map<String, List<String>> instead of Map<String, String>, in this way I will be able to exclude more than one field from the same class:

@Data
@Configuration
@ConfigurationProperties(prefix = "project")
@PropertySource(value = "classpath:application-_test.yaml", factory = YamlPropertySourceFactory.class)
public class ExcludePopulationProperties {

    private Test test;

    @Data
    public static class Test {
        private Service service;
    }

    @Data
    public static class Service {
        private Computator computator;
    }

    @Data
    public static class Computator {
        private Population population;
    }

    @Data
    public static class Population {
        private Map<String, List<String>> exclude;
    }

}

YamlPropertySourceFactory is a class implemented by Baeldung in this guide:
@PropertySource with YAML Files in Spring Boot

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());

        Properties properties = factory.getObject();

        return new PropertiesPropertySource(resource.getResource().getFilename(), properties);
    }

}

Test Class :

@EnableConfigurationProperties
@ContextConfiguration(classes = { ExcludePopulationProperties.class })
@TestPropertySource(properties = { "spring.config.location=classpath:application-_test.yaml" })
@ExtendWith(SpringExtension.class)
class YamlTest {

    @Autowired
    private ExcludePopulationProperties excludePopulationProperties;

    @Test
    void testExternalConfiguration() {
        Map<String, List<String>> map = excludePopulationProperties.getTest().getService().getComputator().getPopulation().getExclude();
        assertNotNull(map);
    }

}

Please note that for Mockito you need to use both, SpringExtension and MockitoExtension:

@EnableConfigurationProperties
@ContextConfiguration(classes = { ExcludePopulationProperties.class })
@Extensions({
        @ExtendWith(SpringExtension.class),
        @ExtendWith(MockitoExtension.class)
})
class YamlTest {

}

Answered By – Paul Marcelin Bejan

Answer Checked By – Cary Denson (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published