Search code examples
javamavenjunitclassloader

JUnit classloader issues when moving to Maven with System properties and static fields


I'm working on converting our legacy build from using Ant to Maven (3.3.3, if that matters), and ran into a snag. Our codebase has a class that initializes a private static field from system properties, which typically are populated by a launch script on application invocation. The unit test which exercises this code is setting the system properties before executing the test. When running the unit test in either Ant or through the Eclipse JUnit runner, everything works fine. When running through maven, it seems that the static field is initialized before the unit test executes, causing the properties to not be present, and the test to fail.

I've put together a sample class and unit test to demonstrate, as I'm not allowed to post the actual code here.

package foo.bar;

public class ValueClass { 
    private static final String SAMPLE_FIELD = "Foo " + System.getProperty("target.value");

    private final myValueField;

    public ValueClass() {
        myValueField = "random text " + SAMPLE_FIELD;
    }

    public String getValueField() { 
        return myValueField;
    }
}

And the corresponding unit test:

package foo.bar;

import org.junit.Test;
import org.junit.BeforeClass;

public class ValueClassTest { 

    @BeforeClass
    public static void setupBeforeClasses() { 
        System.setProperty("target.value", "value from test");
    }

    @Test
    public void testGetValueField() { 
        String expected = "random text Foo value from test";

        ValuesClass valuesClassInstance = new ValuesClass();

        String actual = valuesClassInstance.getValueField();

        assertEquals(expected, actual);
    }  
}

As I mentioned, when I execute using Ant or Eclipse, everything works fine. I've played around with some logging (dropping some log messages into a static block in the ValueClass), and determined that when running in Eclipse or Ant, the class is loaded during the testGetValueField method's execution, and in Maven, the class is loaded sometime before the setupBeforeClasses method is executed. This causes the SAMPLE_FIELD to be initialized with null values from the "target.value" system property.

Any help is greatly appreciated! Rob


Solution

  • If you can set the System properties from the pom.xml, then stop doing it from the @BeforeClass method and try this:

    <project>
            [...]
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19.1</version>
            <configuration>
              <systemPropertyVariables>
                <propertyName>propertyValue</propertyName>
                <buildDirectory>${project.build.directory}</buildDirectory>
                [...]
              </systemPropertyVariables>
            </configuration>
          </plugin>
        </plugins>
      </build>
            [...]
    </project>