◆ Problem
You need a quick and easy way to set and retrieve variable data in your tests at runtime.
139 Use Java system properties
◆ Background
Sometimes you need a simple and quick way to pass a small amount of variable data to your test cases. Hard coding the data and recompiling the test case every time you want to change a value is more time consuming and less efficient than making the variable something that can be passed in on the command line. A database is too heavy duty to set up and use in many situations (or the database might not be designed or finished when you need to be coding and testing). Even reading in a properties file to retrieve variables can be time consuming and cause undesirable overhead if there are only a few variables.
You shouldn’t have to go to great lengths just to parameterize some test data for a one-off test or a test that occurs early in the project that you’ve written to try out a new API or investigate a design issue. Yet it would be nice to always stay within the realm of portable Java solutions. You should never need to hard code a path to a file on your Windows C: drive in a test case when you might turn around and e-mail that test to your colleague who wants to run it quickly from the com- mand line without editing the source and recompiling it.
◆ Recipe
Use Java system properties on the command line, in your IDE settings, or in Ant to pass parameterized data values into the system environment of the JVM where they can be retrieved using methods of the java.lang.System class.
There are several ways to set a system property, depending on the way you launch tests. How you set the property also depends on whether you want to set the prop- erty programmatically or outside your test. The simplest is to key it in at the com- mand prompt using the standard command-line option -Dpropertyname=value syntax accepted by the java application launcher. The propertyname is the name of the system property you want to create, and value is what you want the property to be set to, both of which can be any valid Java string. You can choose any name you want, but if you choose a name of one of the standard Java system properties, you override its value (which you probably don’t want to do). Most of the standard prop- erties begin with "java." but you can refer to a list of their names (also called keys) in the Javadoc for java.lang.System.getProperties().1
1 The Javadoc does not contain a complete list—the keys listed there are guaranteed to be available, but there may be more.
140 CHAPTER 5
Working with test data
The following command-line snippet demonstrates setting two system proper- ties. The first is given the uninteresting name FOO and the value BAR and the sec- ond is given the name spaces.are.ok and the value “string with spaces”:
java –DFOO=BAR –Dspaces.are.ok="string with spaces" [class] [arguments]
ANT TIP In Ant, system properties can be passed directly to the <junit> task with one or more <sysproperty> subelements as shown here. In an Ant build file, this is how you set the same FOO and spaces.are.ok proper- ties we set on the command line in the previous example.
<junit printsummary="yes" dir="${basedir}" fork="yes">
<sysproperty key="FOO" value="BAR"/>
<sysproperty key="spaces.are.ok" value="string with spaces"/>
<test name="some.company.SomeTestCase"/>
</junit>
NOTE Eclipse—If you are running your tests inside the Eclipse IDE, you can set system properties for JUnit test runs by using the Run wizard for JUnit run configurations as shown in figure 5.1. Other IDEs (NetBeans, IntelliJ IDEA, and JBuilder) have similar capabilities for passing system proper- ties to their built-in JUnit test runners.
Regardless of the execution mechanism (whether you use the command line, Ant, or Eclipse), you access these system property values from your test by using
Figure 5.1
Setting system property arguments in Eclipse’s JUnit Run wizard
TE AM FL Y
Team-Fly®
141 Use Java system properties
java.lang.System.getProperty(Stringkey). The name you give the property on the command line or in the key attribute of the <sysproperty> subelement deter- mines the string you must pass to System.getProperty(String key) to retrieve its value. Listing 5.1 shows a complete example of getting two system properties and using them in an assertion.
package junit.cookbook.testdata;
import junit.framework.TestCase;
public class SystemPropertyDemo extends TestCase {
private String fooProperty = System.getProperty("FOO");
private String spacesProperty = System.getProperty("spaces.are.ok");
public void testSystemProperty() { if (fooProperty == null) {
fail("Expected 'FOO' to be set as a system property.");
} else {
assertEquals("BAR", System.getProperty("FOO"));
} } }
You can run SystemPropertyDemo with any test runner, but here is the command line to run it with the text-based test runner:
java –DFOO=BAR –Dspaces.are.ok="string with spaces" -cp .;junit.jar
➾ junit.textui.TestRunner junit.cookbook.testdata.SystemPropertyDemo
◆ Discussion
This recipe is most useful for String variables or primitive data type variables whose values can easily be converted from a String using the standard JDK conversion methods, such as Double.parseDouble(Strings) or Boolean.getBoolean(Strings). In addition to being useful for dynamically setting a small number of variable values, this recipe is useful for setting configuration variables for your test frame- work. For example, a system property may be used to set a default global or package- level logging threshold (handy if you’re using a logger for logging test results or test debug messages).
The overloaded System.getProperty(Stringkey, StringdefaultValue) method returns a default value if a system property’s value has not been set. For example, you may set a default value for the database server hostname to use when running a
Listing 5.1 SystemPropertyDemo
142 CHAPTER 5
Working with test data
test locally on your desktop, which you know will be overridden with QA’s test data- base hostname during the automated build. Here’s an example of that usage:
String hostName = System.getProperty("database.hostname","localhost");
Two particular built-in Java system properties are worth special mention not only because they are always available from any Java runtime on any platform but also because they are relative to the current user’s name and platform-specific temp directory. They are user.home and java.io.tmpdir. On Windows XP, these have the following values (“My User” would be replaced with your actual user name on your machine):
user.home = C:\Documents and Settings\My User java.io.tmpdir = C:\DOCUME~2\MYUSER~1\LOCALS~1\Temp\
On UNIX, user.home usually defaults to something similar to /home/myuser and java.io.tmpdir resolves to /tmp.
The user.home property can be useful for reading in user settings related to test data configuration, such as the local test data repository location. The java.io.
tmpdir property can be useful for writing out temporary data files during testing, and it is the directory in which java.io.File.createTempFile(String prefix, String suffix) writes temporary files.
◆ Related
■ 5.6—Use a file-based test data repository