21

Our web app uses SystemPropertyPlaceholder to load property files depending on the value of a system property (see below)

The default setup for running it locally is stored in application.properties. On the production server we currently just set "env" to "production" before deploying the app and it will load production.properties.

Now for testing the app a test.properties file should be used.

If I run all of the tests say in our jenkins build, adding -Denv=test will work as expected. But what if I just want to run a single test in Eclipse with the integrated JUnit runner?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, locations = {"classpath:application-context.xml" })
public class SomeTest {

Is there any way to tell my test it should set the system property "env" to "test" BEFORE Spring is loaded up? Because using MethodInvokingFactoryBean will only set it afterwards for some reason, even if I set it before loading my property files:

<bean id="systemPrereqs"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" value="#{@systemProperties}" />
    <property name="targetMethod" value="putAll" />
    <property name="arguments">
        <!-- The new Properties -->
        <util:properties>
            <prop key="env">test</prop>
        </util:properties>
    </property>
</bean>

<bean
    class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="searchContextAttributes" value="true" />
    <property name="contextOverride" value="true" />
    <property name="ignoreResourceNotFound" value="true" />
    <property name="locations">
        <list>
            <value>classpath:application.properties</value>
            <value>classpath:${env}.properties</value>
            <value>${config}</value>
        </list>
    </property>
</bean>

<bean id="managerDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="username">
        <value>${database.username}</value>
    </property>
    <property name="password">
        <value>${database.password}</value>
    </property>
    <property name="url">
        <value>${database.url}</value>
    </property>

</bean>

With the database properties defined inside application.properties, production.properties and test.properties.

The point is, of course that I want to use the same context file for all environments, otherwise I could just tell my test to use a different context where I set The PropertyPlaceholder property "location" to test.properties... But I want my tests to also cover my context so that any errors there are caught as early as possible (I'm doing end to end tests on our web app with spring-web-mvc which loads up the entire web app providing some nice feedback there and I don't want to loose that).

So far the only way I can see might be to configure the JUnit runner to include some system property setting argument, though I don't know how to do that..

Pete
  • 9,930
  • 22
  • 87
  • 134
  • I would say use profiles in those profiles import the proper files you need. Looks like you are reinventing the wheel. With profile you can simply add `@ActiveProfiles` to your test case to have the proper things loaded. Instead od `-Denv=test` you would then use `-Dspring.active.profiles=test` – M. Deinum Feb 19 '15 at 08:26

3 Answers3

45

I am working on exactly the same problem now and hopefully found the way. You can call System.setProperty() into the static initializer of your test case.

AlexR
  • 109,181
  • 14
  • 116
  • 194
  • 3
    While this will work when running an individual test, it may not necessarily work when running multiple tests, as the Spring context may be reused across multiple tests. – pimlottc Apr 23 '15 at 20:35
  • @pimlottc, IMHO running multiple tests does not cause any problem in this case. The catch is that we have to set system property before initialization of spring context. This is achieved by using static initializer. If all tests cases that share the same spring context set this property (that is the case) the spring context will be initialized correctly. – AlexR Apr 23 '15 at 21:30
  • Yes, I agree, if the static initializer is present in every test class sharing the context. This may not be feasible in some situations. – pimlottc Apr 23 '15 at 23:09
19

In Eclipse, right-click the JUnit test class, select Run As > Run Configurations..., then go to Arguments tab, and under VM Arguments, add in the system property entry, e.g. -Dcatalina.base=C:\programs\apache-tomcat-7.0.32

bratan
  • 3,137
  • 1
  • 14
  • 11
  • 9
    Is there any way to do this for all tests by default, so you don't have to manually set this property for each test? – Stewart Mar 28 '16 at 22:23
0

You could try to use depends-on attribute to have method invoking bean run before others

bmichalik
  • 141
  • 5