A collection of JUnit rules for testing code which uses java.lang.System.
When your test reads a system property, you have to set it before the test and restore its original value afterwards. Use the ClearSystemProperty and ProvideSystemProperty rules for this purpose.
When your test changes a system property, you should restore its original value after the test. The RestoreSystemProperties rule does this for you.
Use the ExpectedSystemExit rule to test code that calls System.exit(…). Verify that
System.exit(…) is called, verify the status code of this call or check assertions afterwards.
Use the ProvideSecurityManager rule to provide a special security manager for your test. The system's security manager is restored after the test.
Use the StandardErrorStreamLog rule
to capture and verify the text, that your test writes to System.err.
Use the TextFromStandardInputStream rule
to provide text, that your test reads from System.in.
Use the StandardOutputStreamLog rule
to capture and verify the text, that your test writes to System.out.
The ClearSystemProperty rule deletes the property before the test and restores the original value of the property when the test is finished.
public void MyTest {
@Rule
public final ClearSystemProperty myPropertyIsCleared
= new ClearSystemProperty("MyProperty");
@Test
public void overrideProperty() {
assertNull(System.getProperty("MyProperty"));
}
}
The ProvideSystemProperty rule provides an arbitrary value for a system property to a test. After the test the original value is restored.
public void MyTest {
@Rule
public final ProvideSystemProperty myPropertyHasMyValue
= new ProvideSystemProperty("MyProperty", "MyValue");
@Rule
public final ProvideSystemProperty otherPropertyIsMissing
= new ProvideSystemProperty("OtherProperty", null);
@Test
public void overrideProperty() {
assertEquals("MyValue", System.getProperty("MyProperty"));
assertNull(System.getProperty("OtherProperty"));
}
}
You could also use a single instance of the rule to achieve the same effect:
public void MyTest {
@Rule
public final ProvideSystemProperty properties
= new ProvideSystemProperty("MyProperty", "MyValue").and("OtherProperty", null);
@Test
public void overrideProperty() {
assertEquals("MyValue", System.getProperty("MyProperty"));
assertNull(System.getProperty("OtherProperty"));
}
}
You can use a properties file to supply properties for the ProvideSystemProperty rule. The file can be from the file system or the class path. In the first case use
@Rule
public final ProvideSystemProperty properties
= ProvideSystemProperty.fromFile("/home/myself/example.properties");
and in the second case use
@Rule
public final ProvideSystemProperty properties
= ProvideSystemProperty.fromResource("example.properties");
The RestoreSystemProperties rule restores the original value of the property when the test is finished.
public void MyTest {
@Rule
public final RestoreSystemProperties restoreSystemProperties
= new RestoreSystemProperties("MyProperty");
@Test
public void overrideProperty() {
//after the test the original value of "MyProperty" will be restored.
System.setProperty("MyProperty", "other value");
...
}
}
You want to verify the text, which your code writes to System.err or System.out. The StandardErrorStreamLog and StandardOutputStreamLog rule are logging everything written to System.err or System.out. The text is available by calling getLog().
public void MyTest {
@Rule
public final StandardErrorStreamLog log = new StandardErrorStreamLog();
@Test
public void overrideProperty() {
System.err.print("hello world");
assertEquals("hello world", log.getLog());
}
}
public void MyTest {
@Rule
public final StandardOutputStreamLog log = new StandardOutputStreamLog();
@Test
public void overrideProperty() {
System.out.print("hello world");
assertEquals("hello world", log.getLog());
}
}
The TextFromStandardInputStream rule helps you
to create tests for classes which read from
System.in. You specify the text provided by
System.in, by calling
provideText(String).
The example's class under test reads two numbers from
System.in and calculates the sum of these numbers.
import java.util.Scanner;
public class Summarize {
public static int sumOfNumbersFromSystemIn() {
Scanner scanner = new Scanner(System.in);
int firstSummand = scanner.nextInt();
int secondSummand = scanner.nextInt();
return firstSummand + secondSummand;
}
}
import static org.junit.Assert.*;
import static org.junit.contrib.java.lang.system.TextFromStandardInputStream.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.TextFromStandardInputStream;
public class SummarizeTest {
@Rule
public final TextFromStandardInputStream systemInMock
= emptyStandardInputStream();
@Test
public void summarizesTwoNumbers() {
systemInMock.provideText("1\n2\n");
assertEquals(3, Summarize.sumOfNumbersFromSystemIn());
}
}
If your code calls System.exit(), then your test
stops and doesn't finish. The ExpectedSystemExit
rule allows in-test specification of expected
System.exit() calls. Furthermore you cannot use
JUnit's assert methods because of the abnormal termination of
your code. As a substitute you can provide an
Assertion object to the
ExpectedSystemExit rule.
Some care must be taken if your system under test creates a
new thread and this thread calls System.exit(). In
this case you have to ensure that the test does not finish
before System.exit() is called.
public class AppWithExit {
public static String message;
public static void doSomethingAndExit() {
message = "exit ...";
System.exit(1);
}
public static void doNothing() {
}
}
public void AppWithExitTest {
@Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
@Test
public void exits() {
exit.expectSystemExit();
AppWithExit.doSomethingAndExit();
}
@Test
public void exitsWithStatusCode1() {
exit.expectSystemExitWithStatus(1);
AppWithExit.doSomethingAndExit();
}
@Test
public void writesMessage() {
exit.expectSystemExitWithStatus(1);
exit.checkAssertionAfterwards(new Assertion() {
public void checkAssertion() {
assertEquals("exit ...", AppWithExit.message);
}
});
AppWithExit.doSomethingAndExit();
}
@Test
public void systemExitWithStatusCode1() {
exit.expectSystemExitWithStatus(1);
AppWithExit.doSomethingAndExit();
}
@Test
public void noSystemExit() {
AppWithExit.doNothing();
//passes
}
}
If you need a special security manager to test your code, you may provide it by using the ProvideSecurityManager rule. This rule replaces the system's security manager with yours throughout the test
public void MyTest {
private final MySecurityManager securityManager
= new MySecurityManager();
@Rule
public final ProvideSecurityManager provideSecurityManager
= new ProvideSecurityManager(securityManager);
@Test
public void overrideProperty() {
assertEquals(securityManager, System.getSecurityManager());
}
}
Marc Philipp (mail@marcphilipp.de)
Stefan Birkner (mail@stefan-birkner.de)
Stefan Birkner (mail@stefan-birkner.de)