33

I have a jUnit Test that has its own properties file(application-test.properties) and its spring config file(application-core-test.xml).

One of the method uses an object instantiated by spring config and that is a spring component. One of the members in the classes derives its value from application.properties which is our main properties file. While accessing this value through jUnit it is always null. I even tried changing the properties file to point to the actual properties file, but that doesnt seem to work.

Here is how I am accessing the properties file object

@Component
@PropertySource("classpath:application.properties")
public abstract class A {

    @Value("${test.value}")
    public String value;

    public A(){
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }

    public A(String text) {
        this();
        // do something with text and value.. here is where I run into NPE
    }

}

public class B extends A { 
     //addtnl code

    private B() {

    }


    private B(String text) {
         super(text)
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:META-INF/spring/application-core-test.xml",
                             "classpath:META-INF/spring/application-schedule-test.xml"})
@PropertySource("classpath:application-test.properties")
public class TestD {

    @Value("${value.works}")
    public String valueWorks;

    @Test
    public void testBlah() {     
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        B b= new B("blah");
        //...addtnl code

    }    
}      
soufrk
  • 825
  • 1
  • 10
  • 24
Nikhil Das Nomula
  • 1,863
  • 5
  • 31
  • 50
  • How are you instantiating an instance of `A`? My guess is that you are using `new` rather than looking it up from the ApplicationContext – lance-java Oct 06 '15 at 16:01
  • So shouldn't application.properties in the @PropertySource read application-test.properties? – Robert Moskal Oct 06 '15 at 16:02
  • @Lance Java: Yes I am using new. Will try looking up from ApplicationContext.. – Nikhil Das Nomula Oct 06 '15 at 16:03
  • @RobertMoskal I tried that and did'nt seem to work either. – Nikhil Das Nomula Oct 06 '15 at 16:03
  • @user1707141 using `new` means that spring is not managing the object and does not have a chance to populate it. – lance-java Oct 06 '15 at 16:04
  • This is a good argument for using [constructor injection](https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection) rather than [setter/field injection](https://en.wikipedia.org/wiki/Dependency_injection#Setter_injection) – lance-java Oct 06 '15 at 16:08
  • Aah ok, however when I use new object for running the application normally it is picking up the value(from properties file). Its only in jUnit that the value is null. I just tried to fetch the object from the applicationContext it says that the bean does not exist. I am surprised as to why it come up with that as it is annotated with @Component – Nikhil Das Nomula Oct 06 '15 at 16:12
  • 1
    You will need either @ComponentScan or `` to pick up your @Component – lance-java Oct 07 '15 at 12:16

7 Answers7

40

Firstly, application.properties in the @PropertySource should read application-test.properties if that's what the file is named (matching these things up matters):

@PropertySource("classpath:application-test.properties")

That file should be under your /src/test/resources classpath (at the root).

I don't understand why you'd specify a dependency hard coded to a file called application-test.properties. Is that component only to be used in the test environment?

The normal thing to do is to have property files with the same name on different classpaths. You load one or the other depending on whether you are running your tests or not.

In a typically laid out application, you'd have:

src/test/resources/application.properties

and

src/main/resources/application.properties

And then inject it like this:

@PropertySource("classpath:application.properties")

The even better thing to do would be to expose that property file as a bean in your spring context and then inject that bean into any component that needs it. This way your code is not littered with references to application.properties and you can use anything you want as a source of properties. Here's an example: how to read properties file in spring project?

tostao
  • 2,803
  • 4
  • 38
  • 61
Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
31

As for the testing, you should use from Spring 4.1 which will overwrite the properties defined in other places:

@TestPropertySource("classpath:application-test.properties")

Test property sources have higher precedence than those loaded from the operating system's environment or Java system properties as well as property sources added by the application like @PropertySource

sendon1982
  • 9,982
  • 61
  • 44
  • 1
    Thanks! In spring-boot 2.1.2, `@TestPropertySource` works with `@ContextConfiguration` in a JUnit test, where `@PropertySource` doesn't. – ttiurani Mar 08 '19 at 07:34
4

I faced the same issue, spent too much calories searching for the right fix until I decided to settle down with file reading:

Properties configProps = new Properties();
InputStream iStream = new ClassPathResource("myapp-test.properties").getInputStream();
InputStream iStream = getConfigFile();
configProps.load(iStream);
Siena
  • 778
  • 10
  • 23
1

If you are using a jar file inside a docker container, and the resource properties file, say application.properties is packaged within the same classes directory that contains the java(this is what IntelliJ IDE does automatically for resources file stored in /src/main/resources), this is what helped me:

public static Properties props = new Properties();

    static {
        try {
            props.load(
                    Thread
                            .currentThread()
                            .getContextClassLoader()
                            .getResourceAsStream("application.properties")
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Most other methods either only worked inside the IDE or inside the Docker. This one works in both.

loud_mouth
  • 23
  • 1
  • 3
1
if you want to load a few properties, I found a good way in the spring 
ReflectionTestUtils. 


@Before
Public void setup(){
 ReflectionTestUtils.setField(youclassobject, "value", "yourValue")
 
}

>you can follow this link as well for more details https://roytuts.com/mock-an-    autowired-value-field-in-spring-with-junit-mockito/
0

How to read values from properties file while running JUnit Test ? ReflectionTestUtils is the simplest way to set values for any variable that is reading values from properties file.

Inside the setup function, add the below line:

ReflectionTestUtils.setField(ObjectName, "VariableToSetValue", "Value");

Eg: ReflectionTestUtils.setField(studentService, "uri", "http://example.com");

-1

The answer to your question is that @PropertySource("classpath:application-test.properties") does not work outside of spring boot test. Only when you have @SpringBootTest only then this works and properties are automatically injected.

ACV
  • 9,964
  • 5
  • 76
  • 81
  • First this is an old question and pre-dates Spring Boot. Second this is not true. You can use it in a regular Spring based test with `@ContextConfiguration` and the proper extension as well, as well as the different sliced tests. So this answer simply isn't giving the correct facts. – M. Deinum Jun 16 '23 at 21:04