Spring jUnit Testing properties file
Asked Answered
M

7

36

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

    }    
}      
Mindimindless answered 6/10, 2015 at 15:58 Comment(8)
How are you instantiating an instance of A? My guess is that you are using new rather than looking it up from the ApplicationContextEsophagus
So shouldn't application.properties in the @PropertySource read application-test.properties?Unpolite
@Lance Java: Yes I am using new. Will try looking up from ApplicationContext..Mindimindless
@RobertMoskal I tried that and did'nt seem to work either.Mindimindless
@user1707141 using new means that spring is not managing the object and does not have a chance to populate it.Esophagus
This is a good argument for using constructor injection rather than setter/field injectionEsophagus
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 @ComponentMindimindless
You will need either @ComponentScan or <context:component-scan/> to pick up your @ComponentEsophagus
U
42

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?

Unpolite answered 6/10, 2015 at 16:24 Comment(3)
I have made the suggested changes, but it is still not loading the value from the properties file... is there something that I am missingMindimindless
Are your classpaths set up? How do you run this?Unpolite
Yes the classpaths are set up. The code above in class D mentions how it is set up.. I am using eclipse and I do a run as -> jUnit testMindimindless
R
32

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

Ruffner answered 25/4, 2017 at 10:34 Comment(1)
Thanks! In spring-boot 2.1.2, @TestPropertySource works with @ContextConfiguration in a JUnit test, where @PropertySource doesn't.Nonreturnable
A
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);
Abroad answered 2/10, 2020 at 18:40 Comment(1)
Thank you, I was getting dangerously low on calories too.Novice
F
3

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/

Flawed answered 16/1, 2023 at 20:9 Comment(0)
T
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.

Terena answered 3/7, 2022 at 21:9 Comment(0)
G
1

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

Glyconeogenesis answered 15/3, 2023 at 10:49 Comment(0)
K
-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.

Kinnon answered 16/6, 2023 at 21:2 Comment(1)
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.Scarcely

© 2022 - 2024 — McMap. All rights reserved.