Populating Spring @Value during Unit Test Populating Spring @Value during Unit Test java java

Populating Spring @Value during Unit Test


If possible I would try to write those test without Spring Context. If you create this class in your test without spring, then you have full control over its fields.

To set the @value field you can use Springs ReflectionTestUtils - it has a method setField to set private fields.

@see JavaDoc: ReflectionTestUtils.setField(java.lang.Object, java.lang.String, java.lang.Object)


Since Spring 4.1 you could set up property values just in code by using org.springframework.test.context.TestPropertySource annotation on Unit Tests class level. You could use this approach even for injecting properties into dependent bean instances

For example

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = FooTest.Config.class)@TestPropertySource(properties = {    "some.bar.value=testValue",})public class FooTest {  @Value("${some.bar.value}")  String bar;  @Test  public void testValueSetup() {    assertEquals("testValue", bar);  }  @Configuration  static class Config {    @Bean    public static PropertySourcesPlaceholderConfigurer propertiesResolver() {        return new PropertySourcesPlaceholderConfigurer();    }  }}

Note: It's necessary to have instance of org.springframework.context.support.PropertySourcesPlaceholderConfigurer in Spring context

Edit 24-08-2017: If you are using SpringBoot 1.4.0 and later you could initialize tests with @SpringBootTest and @SpringBootConfiguration annotations. More info here

In case of SpringBoot we have following code

@SpringBootTest@SpringBootConfiguration@RunWith(SpringJUnit4ClassRunner.class)@TestPropertySource(properties = {    "some.bar.value=testValue",})public class FooTest {  @Value("${some.bar.value}")  String bar;  @Test  public void testValueSetup() {    assertEquals("testValue", bar);  }}


Don't abuse private fields get/set by reflection

Using reflection as that is done in several answers here is something that we could avoid.
It brings a small value here while it presents multiple drawbacks :

  • we detect reflection issues only at runtime (ex: fields not existing any longer)
  • We want encapsulation but not a opaque class that hides dependencies that should be visible and make the class more opaque and less testable.
  • it encourages bad design. Today you declare a @Value String field. Tomorrow you can declare 5 or 10 of them in that class and you may not even be straight aware that you decrease the design of the class. With a more visible approach to set these fields (such as constructor) , you will think twice before adding all these fields and you will probably encapsulate them into another class and use @ConfigurationProperties.

Make your class testable both unitary and in integration

To be able to write both plain unit tests (that is without a running spring container) and integration tests for your Spring component class, you have to make this class usable with or without Spring.
Running a container in an unit test when it is not required is a bad practice that slows down local builds : you don't want that.
I added this answer because no answer here seems to show this distinction and so they rely on a running container systematically.

So I think that you should move this property defined as an internal of the class :

@Componentpublic class Foo{       @Value("${property.value}") private String property;    //...}

into a constructor parameter that will be injected by Spring :

@Componentpublic class Foo{       private String property;         public Foo(@Value("${property.value}") String property){       this.property = property;    }    //...         }

Unit test example

You can instantiate Foo without Spring and inject any value for property thanks to the constructor :

public class FooTest{   Foo foo = new Foo("dummyValue");   @Test   public void doThat(){      ...   }}

Integration test example

You can injecting the property in the context with Spring Boot in this simple way thanks to the properties attribute of @SpringBootTest :

@SpringBootTest(properties="property.value=dummyValue")public class FooTest{       @Autowired   Foo foo;        @Test   public void doThat(){       ...   }    }

You could use as alternative @TestPropertySource but it adds an additional annotation :

@SpringBootTest@TestPropertySource(properties="property.value=dummyValue")public class FooTest{ ...}

With Spring (without Spring Boot), it should be a little more complicated but as I didn't use Spring without Spring Boot from a long time I don't prefer say a stupid thing.

As a side note : if you have many @Value fields to set, extracting them into a class annotated with @ConfigurationProperties is more relevant because we don't want a constructor with too many arguments.