0

I am a newbie to Spring and I am trying to load properties file using Spring framework, I am able to successfully load all the properties from junit test but when I am trying to implement the unit test as function it throws NPE-

my junit class (which is working as expected)

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles(profiles = "test")
@ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestPropertiesTest2 extends TestCase {

    @Autowired
    GenericEnv env;

    @Autowired
    WebPropertiesLoader wpl;

    @Test
    public void testAppProperties() {

        System.out.println("Running MiniConfigSpringPropertiesTest ...");

        System.out.println("Environment        : " + env.toString());

        System.out.println("Database Properties: " + wpl.toString());
    }

}

My implementation class (Which is exhibiting NPE) :

@ActiveProfiles(profiles = "test")
@ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestProperties {

    @Autowired
    GenericEnv env;

    @Autowired
    WebPropertiesLoader wpl;

    public static void main(String[] args) {
        GlueTestProperties gp = new GlueTestProperties();
        gp.callme();


    }


    private void callme(){

 System.out.println("Running ConfigSpringPropertiesTest ...");

        System.out.println("Environment        : " + env.toString());

        System.out.println("Database Properties: " + wpl.toString());
    }
}

WebPropertiesLoader bean :

@Component
public class WebPropertiesLoader {

    @Value("${bank.ease.login.url}")
    public String easeLoginUrl;

    @Value("${bank.browser.name}")
    public String browserName;

    @Value("${bank.browser.version}")
    public String browserVersion;

    @Value("${webdriver.chrome.driver}")
    public String chromeDriver;

    @Value("${webdriver.ie.driver}")
    public String ieDriver;

    @Value("${bank.web.feature.location}")
    public String webFeatureLocation;

    @Value("${bank.web.test.location}")
    public String webTestLocation;

    @Value("${bank.event.log}")
    public String eventLog;

    @Value("${bank.epoxy.backend}")
    public String epoxyBackend;

    @Value("${bank.epoxy.host}")
    public String epoxyHost;

    @Value("${bank.epoxy.port}")
    public String epoxyPort;

    @Value("${bank.epoxy.debug}")
    public String epoxyDebug;

    @Value("${bank.epoxy.implicitWait}")
    public String epoxyImplicitWait;

    @Value("${bank.epoxy.timeout}")
    public String epoxyTimeOut;

    @Value("${bank.epoxy.default.url}")
    public String epoxyDefaultURL;

    @Value("${bank.sassy.url}")
    public String sassyUrl;

    @Value("${bank.transite.url}")
    public String transiteUrl;

    @Value("${bank.transite.login.url}")
    public String transiteLoginUrl;


    public String getBrowserName() {
        return browserName;
    }

    public String getBrowserVersion() {
        return browserVersion;
    }

    public String getChromeDriver() {
        return chromeDriver;
    }

    public String getEpoxyDefaultURL() {
        return epoxyDefaultURL;
    }

    public String getSassyUrl() {
        return sassyUrl;
    }

    public String getTransiteUrl() {
        return transiteUrl;
    }

    public String getTransiteLoginUrl() {
        return transiteLoginUrl;
    }

    public String getIeDriver() {
        return ieDriver;
    }

    public String getWebFeatureLocation() {
        return webFeatureLocation;
    }

    public String getWebTestLocation() {
        return webTestLocation;
    }

    public String getEventLog() {
        return eventLog;
    }

    public String getEpoxyBackend() {
        return epoxyBackend;
    }

    public String getEpoxyHost() {
        return epoxyHost;
    }

    public String getEpoxyPort() {
        return epoxyPort;
    }

    public String getEpoxyDebug() {
        return epoxyDebug;
    }

    public String getEpoxyImplicitWait() {
        return epoxyImplicitWait;
    }

    public String getEpoxyTimeOut() {
        return epoxyTimeOut;
    }


    public String getEaseLoginUrl() {
        return easeLoginUrl;
    }

    @Override
    public String toString() {
        return "Ease application Default Properties [browserName=" + browserName + ", browserVersion=" + browserVersion
                + ", chromeDriver=" + chromeDriver + ", ieDriver=" + ieDriver + ", webFeatureLocation="
                + webFeatureLocation + ", webTestLocation=" + webTestLocation + ", eventLog=" + eventLog
                + ", epoxyBackend=" + epoxyBackend + ", epoxyHost=" + epoxyHost + ", epoxyPort=" + epoxyPort
                + ", epoxyDebug=" + epoxyDebug + ", epoxyImplicitWait=" + epoxyImplicitWait + ", epoxyTimeOut="
                + epoxyTimeOut + ", epoxyDefaultURL=" + epoxyDefaultURL + ", easeLoginUrl=" + easeLoginUrl + "]";
    }

}

Test env bean :

@Component
public class TestEnv implements GenericEnv {

    private String envName = "test";

    @Value("${profile.name}")
    private String profileName;

    public String getEnvName() {
        return envName;
    }

    public void setEnvName(String envName) {
        this.envName = envName;
    }

    public String getProfileName() {
        return profileName;
    }

    public void setProfileName(String profileName) {
        this.profileName = profileName;
    }

    @Override
    public String toString() {
        return "TestEnv [envName=" + envName + ", profileName=" + profileName
                + "]";
    }

}

Context xml used :

?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.xsd
       http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd 
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- scans for annotated classes in the com.company package -->
    <context:component-scan base-package="com.glue.commons" />

    <!-- enables annotation based configuration -->
    <!-- <context:annotation-config /> -->

    <beans profile="dev">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-dev files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-web-default.properties, classpath:properties/application-web-dev.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.dev package -->
        <context:component-scan base-package="com.glue.env.dev" />
    </beans>

    <beans profile="test">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-test files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-web-default.properties, classpath:properties/application-web-qa2.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.test package -->
        <context:component-scan base-package="com.glue.env.test" />
    </beans>

    <beans profile="prod">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-prod files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-web-default.properties, classpath:properties/application-web-prod.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.prod package -->
        <context:component-scan base-package="com.glue.env.prod" />
    </beans>
    <beans profile="dev">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-dev files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-api-default.properties, classpath:properties/application-api-dev.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.dev package -->
        <context:component-scan base-package="com.glue.env.dev" />
    </beans>

    <beans profile="test">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-test files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-api-default.properties, classpath:properties/application-api-qa2.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.test package -->
        <context:component-scan base-package="com.glue.env.test" />
    </beans>

    <beans profile="prod">
        <!-- allows for ${} replacement in the spring xml configuration from the 
            application-default.properties, application-prod files on the classpath -->
        <context:property-placeholder
            location="classpath:properties/application-api-default.properties, classpath:properties/application-api-prod.properties"
            ignore-unresolvable="true" />

        <!-- scans for annotated classes in the com.env.prod package -->
        <context:component-scan base-package="com.glue.env.prod" />
    </beans>

Thanks in advance, please forgive me if I've made some silly mistake, but I need your help.

Shek
  • 1,543
  • 6
  • 16
  • 34

2 Answers2

1

If you use the main method to create it then spring won't know anything about this class so it won't autowire any classes - you get nulls in all fields annotated with @Autowired.

Your JUnit is working correctly because it is instantiated with spring aware junit runner.

Krzysztof Krasoń
  • 26,515
  • 16
  • 89
  • 115
0

I am able to get the properties to load. Issue was that as @krzyk pointed out my implementation class was not spring aware hence it was not able to load the profile from my context xml and to make it aware of my profile bean I had to pass vm argument through my main class, following code change and approach helped me :

my implementation class look like this now:

@ContextConfiguration("classpath:spring/xml-config-context.xml")
public class GlueTestProperties {


 private GlueTestProperties() {

    }

    private static ApplicationContext context;

    public static GenericEnv getEnv() {
        return getContext().getBean(TestEnv.class);
    }

    public static WebPropertiesLoader getWebProperties() {
        return getContext().getBean(WebPropertiesLoader.class);
    }

    public static ApiPropertiesLoader getApiProperties() {
        return getContext().getBean(ApiPropertiesLoader.class);
    }

    private static ApplicationContext getContext() {
        if (null == context) {
            init();
        }
        return context;
    }

    private static synchronized void init() {
        context = new ClassPathXmlApplicationContext("spring/xml-config-context.xml");
    }

}

I am passing following as vm argument : -Dspring.profiles.active=test

Or second approach would be you have to take out

<context:property-placeholder
            location="classpath:properties/application-web-default.properties, classpath:properties/application-web-qa2.properties"
            ignore-unresolvable="true" />

from your <bean/> and place it out side so that it will be visible for main class and you do not have to pass vm arguments here.

Shek
  • 1,543
  • 6
  • 16
  • 34
  • Why did you add this as an answer? If it works after reading my answer then this one is not needed. If it still doesn't work try comments/or editing your question. – Krzysztof Krasoń Jun 29 '16 at 19:44
  • Thanks for your help @krzyk, you have indeed given me a point to start, but it was much more than just spring awareness, however to thank you I am upvoting your answer. thanks – Shek Jun 29 '16 at 19:51