A collection of JUnit rules for testing code that uses java.lang.System.
The scope of System Rules is divided into five sections.
Command-line applications read from the command-line and write to it. Use SystemErrRule, SystemOutRule and TextFromStandardInputStream to provide the input text and verify the output.
Applications sometimes unintentionally write to System.out
  or System.err. Ensure that this does not happen by using
  DisallowWriteToSystemOut and
  and DisallowWriteToSystemErr.
  
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 the application terminated.
If your test deals with system properties, you have to set them and restore them after the test. Use the ClearSystemProperties, ProvideSystemProperty and RestoreSystemProperties rules for this purpose.
If your test needs to set an environment variable then use the EnvironmentVariables rule.
Use the ProvideSecurityManager rule to provide a specific security manager for your test. The system's security manager is restored after the test.
All examples below are using the @Rule annotation,
		but the rules can be used with the @ClassRule
		annotation, too.
The ClearSystemProperties rule deletes the property before the test and restores the original value of the property when the test is finished.
public class MyTest {
	@Rule
	public final ClearSystemProperties myPropertyIsCleared
	 = new ClearSystemProperties("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 class 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 class 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 undoes changes of all system properties when the test finishes (whether it passes or fails).
public class MyTest {
	@Rule
	public final RestoreSystemProperties restoreSystemProperties
	 = new RestoreSystemProperties();
	@Test
	public void overrideProperty() {
		//after the test the original value of "MyProperty" will be restored.
		System.setProperty("MyProperty", "other value");
		...
	}
}The SystemErrRule and the SystemOutRule
	help you to create tests for classes that write to
	System.err or System.out. They can record
	everything written to System.err or System.out.
	The text is available by calling getLog().
public class MyTest {
	@Rule
	public final SystemErrRule systemErrRule = new SystemErrRule().enableLog();
	@Test
	public void writesTextToSystemErr() {
		System.err.print("hello world");
		assertEquals("hello world", systemErrRule.getLog());
	}
}public class MyTest {
	@Rule
	public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
	@Test
	public void writesTextToSystemOut() {
		System.out.print("hello world");
		assertEquals("hello world", systemOutRule.getLog());
	}
}If you verify logs that contain line separators than the separators
	are different (e.g. Linux: \n, Windows: \r\n).
	Use getLogWithNormalizedLineSeparator() for a log that
	always has the line separator \n.
public class MyTest {
	@Rule
	public final SystemErrRule systemErrRule = new SystemErrRule().enableLog();
	@Test
	public void writesTextToSystemErr() {
		System.err.print(String.format("hello world%n)");
		assertEquals("hello world\n", systemErrRule.getLog());
	}
}public class MyTest {
	@Rule
	public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
	@Test
	public void writesTextToSystemOut() {
		System.out.print(String.format("hello world%n)");
		assertEquals("hello world\n", systemOutRule.getLog());
	}
}If your code under test writes raw binary data to System.err
	or System.out then you can read it by means of
	getLogAsBytes().
public class MyTest {
	@Rule
	public final SystemErrRule systemErrRule = new SystemErrRule().enableLog();
	@Test
	public void writesBytesToSystemErr() {
		byte[] data = { 1, 2, 3, 4, 5 };
		System.err.write(data, 0, data.length);
		assertEquals(data, systemErrRule.getLogAsBytes());
	}
}public class MyTest {
	@Rule
	public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
	@Test
	public void writesBytesToSystemOut() {
		byte[] data = { 1, 2, 3, 4, 5 };
		System.out.write(data, 0, data.length);
		assertEquals(data, systemOutRule.getLogAsBytes());
	}
}The log can be cleared if you want to discard some text that has been written to the log.
public class MyTest {
	@Rule
	public final SystemErrRule systemErrRule = new SystemErrRule().enableLog();
	@Test
	public void writesTextToSystemErr() {
		System.err.print("hello world");
		systemErrRule.clear().
		System.err.print("foo");
		assertEquals("foo", systemErrRule.getLog());
	}
}public class MyTest {
	@Rule
	public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
	@Test
	public void writesTextToSystemOut() {
		System.out.print("hello world");
		systemOutRule.clear().
		System.out.print("foo");
		assertEquals("foo", systemOutRule.getLog());
	}
}The output is still written to System.err and
	System.out. In general this is not necessary. Avoiding
	the output may speed up the test and reduce the clutter on the
	commandline. You can disable the output by calling mute().
	@Rule
public final SystemErrRule systemErrRule = new SystemErrRule().mute();@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().mute();
Muting and logging can be combined.
@Rule
public final SystemErrRule systemErrRule = new SystemErrRule().enableLog().mute();@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog().mute();In case of a failed test it is sometimes helpful to see the output.
	This is when the method muteForSuccessfulTests() comes
	into play.
@Rule
public final SystemErrRule systemErrRule = new SystemErrRule().muteForSuccessfulTests();@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().muteForSuccessfulTests();The TextFromStandardInputStream rule helps you
				to create tests for classes which read from
				System.in. You specify the lines provided by
				System.in, by calling
				provideLines(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.provideLines("1", "2");
    assertEquals(3, Summarize.sumOfNumbersFromSystemIn());
  }
}If you want to test that your class under test handles exception correctly then you can tell TextFromStandardInputStream to throw an exception after all characters have been read.
systemInMock.throwExceptionOnInputEnd(new IOException());or
systemInMock.throwExceptionOnInputEnd(new RuntimeException());The rules DisallowWriteToSystemErr and
  DisallowWriteToSystemOut let tests fail if they try to write to
  System.err or System.out. The rules are a nice
  replacement for static code analysis because they cover external libraries,
  too.
public class MyTest {
  @Rule
  public final DisallowWriteToSystemErr disallowWriteToSystemErr
    = new DisallowWriteToSystemErr();
  @Test
  public void this_test_fails() {
    System.err.println("some text");
  }
}public class MyTest {
  @Rule
  public final DisallowWriteToSystemOut disallowWriteToSystemOut
    = new DisallowWriteToSystemOut();
  @Test
  public void this_test_fails() {
    System.out.println("some text");
  }
}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 class 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 to set an environment variable then use the
  EnvironmentVariables rule. It does all the tedious work for
  setting environment variables and reverts your changes after the test.
public class EnvironmentVariablesTest {
  @Rule
  public final EnvironmentVariables environmentVariables
    = new EnvironmentVariables();
  @Test
  public void setEnvironmentVariable() {
    environmentVariables.set("name", "value");
    assertEquals("value", System.getenv("name"));
  }
}If your test needs some environment variables not to be present then you can clear it.
public class EnvironmentVariablesTest {
@Rule
public final EnvironmentVariables environmentVariables
	= new EnvironmentVariables();
@Test
public void setEnvironmentVariable() {
	environmentVariables.clear("first variable", "second variable");
	assertNull(System.getenv("first variable"));
	assertNull(System.getenv("second variable"));
}
}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 class 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)