1. Overview

In this tutorial, we'll look at how we can set a Java system property for the tests run by Maven.

By doing this, we can ignore tests according to a system property. Or we can override the configuration values by the given property values.

2. Use the Surefire Plugin

We'll first look at the Maven Surefire plugin.

2.1. systemPropertyVariables

Maven Surefire plugin provides the configuration parameter systemPropertyVariables to set system properties. The properties defined here will be available in the unit tests.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.0</version>
            <configuration>
                <systemPropertyVariables>
                    <greet.english>Hello</greet.english>
                </systemPropertyVariables>              
            </configuration>
        </plugin>
    </plugins>
</build>

Here we're configuring the Surefire plugin under the build section. In essence, we're setting a system property with the key as greet.english and the value as Hello.

Now we can access the greet.english property in the unit tests:

public class SystemPropertyTest {
    @Test
    public void shouldAccessSystemProperty_WhenDefinedInSystemPropertyVariables() {
        Assert.assertEquals("Hello", System.getProperty("greet.english"));
    }
}

Here, we have the unit test class, SystemPropertyTest.

2.2. systemProperties

We can also use systemProperties to define system properties. But note that this configuration parameter is deprecated and systemPropertyVariables is the recommended one.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <systemProperties>
            <property>
                <name>greet.spanish</name>
                <value>Hola</value>
            </property>
        </systemProperties>
    </configuration>
</plugin>

In this configuration, we're defining the greet.spanish property with the value of Hola. Since systemProperties is backed by a java.util.Properties object, the XML schema requires us to use a property element.

Now, the greet.spanish property is available to the unit tests:

@Test
public void shouldAccessSystemProperty_WhenDefinedInSystemProperties() {
    Assert.assertEquals("Hola", System.getProperty("greet.spanish"));
}

2.3. systemPropertiesFile

Lastly, we can use the systemPropertiesFile parameter. We must provide the path of a properties file so that Surefire can read the properties inside.

Assume that we have the sample.properties file under the src/test/resources directory:

greet.german=Hallo

When we pass its path to Surefire:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <systemPropertiesFile>src/test/resources/sample.properties</systemPropertiesFile>
    </configuration>
</plugin>

The Surefire plugin reads the file content and creates a system property for greet.german:

@Test
public void shouldAccessSystemProperty_WhenDefinedInSystemPropertiesFile() {
    Assert.assertEquals("Hallo", System.getProperty("greet.german"));
}

3. Use the Failsafe Plugin

Maven Failsafe plugin supports the same configuration parameters as the Surefire plugin.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.22.0</version>
            <configuration>
                <systemPropertyVariables>
                    <greet.english>Hello</greet.english>
                </systemPropertyVariables>
                <systemProperties>
                    <property>
                        <name>greet.spanish</name>
                        <value>Hola</value>
                    </property>
                    <property>
                        <name>greet.spanish</name>
                        <value>Hola</value>
                    </property>
                </systemProperties>
                <systemPropertiesFile>src/test/resources/sample.properties</systemPropertiesFile>
            </configuration>
        </plugin>
    </plugins>
</build>

Here, we're using three different parameters to create system variables.

Note that while the system properties defined by Surefire are available to the unit tests, the properties defined here will be available to the integration tests.

public class SystemPropertyIT {

    @Test
    public void shouldAccessSystemProperty_WhenDefinedInSystemPropertyVariables() {
        Assert.assertEquals("Hello", System.getProperty("greet.english"));
    }

    @Test
    public void shouldAccessSystemProperty_WhenDefinedInSystemProperties() {
        Assert.assertEquals("Hola", System.getProperty("greet.spanish"));
    }

    @Test
    public void shouldAccessSystemProperty_WhenDefinedInSystemPropertiesFile() {
        Assert.assertEquals("Hallo", System.getProperty("greet.german"));
    }
}

Here, we have an integration test class, SystemPropertyIT, accessing the system properties defined.

4. Use the Properties Plugin

Another option is to use the Maven Properties Plugin. It provides some convenient goals to work with the properties.

4.1. Execute set-property

We can add system properties using the set-property goal.

Also, keep in mind that these properties, as well as the previous ones, will only be available during compile time. Thus when the application starts, we can't access these properties. In our case, we'll use them in the tests:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>properties-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <phase>initialize</phase>
                    <goals>
                        <goal>set-system-properties</goal>
                    </goals>
                    <configuration>
                        <properties>
                            <property>
                                <name>myCustomProperty</name>
                                <value>myValue</value>
                            </property>
                        </properties>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Here, we're adding the Properties plugin to our build process. Moreover, we're defining myCustomProperty with the value of myValue. After this point, other plugins can access this system property and use it. However for unit tests to pick it up, we need an additional configuration.

By default, the Surefire and Failsafe plugins run the tests on another process, thus another JVM instance. As a result, properties created by the Properties plugin won't be accessible by the unit tests or integration tests. To solve this issue, we must change the default behavior.

We'll examine the configuration for Surefire, but it is also same for Failsafe:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <forkCount>0</forkCount>
    </configuration>
</plugin>

To disable creating a new JVM when running tests, we're setting the forkCount as 0.

Then we can access myCustomProperty in the unit tests:

public class SetPropertyTest {

    @Test
    public void shouldRun() {
        Assert.assertEquals("myValue", System.getProperty("myCustomProperty"));
    }
}

5. Summary

In this tutorial, we examined different ways to set system properties for our tests. We first looked at the Maven Surefire plugin and then investigated the Failsafe plugin. Lastly, we used the Properties Maven plugin and configured Surefire to work with this setup.

As always the source code for all examples is available on Github.