{"id":25776849,"url":"https://github.com/webcompere/system-stubs","last_synced_at":"2026-01-31T12:10:31.527Z","repository":{"id":40810412,"uuid":"312851969","full_name":"webcompere/system-stubs","owner":"webcompere","description":"System Stubs - Test Doubles for Java System resources","archived":false,"fork":false,"pushed_at":"2024-09-26T08:25:27.000Z","size":585,"stargazers_count":92,"open_issues_count":6,"forks_count":12,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-11-17T12:56:57.174Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webcompere.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-14T16:10:33.000Z","updated_at":"2024-10-23T06:39:58.000Z","dependencies_parsed_at":"2024-09-18T05:03:13.324Z","dependency_job_id":null,"html_url":"https://github.com/webcompere/system-stubs","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcompere%2Fsystem-stubs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcompere%2Fsystem-stubs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcompere%2Fsystem-stubs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webcompere%2Fsystem-stubs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webcompere","download_url":"https://codeload.github.com/webcompere/system-stubs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240987435,"owners_count":19889335,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-27T06:01:32.231Z","updated_at":"2026-01-31T12:10:31.521Z","avatar_url":"https://github.com/webcompere.png","language":"Java","funding_links":[],"categories":["测试"],"sub_categories":[],"readme":"# System Stubs\n\n[![Build status](https://ci.appveyor.com/api/projects/status/r943gjn189rlxts9/branch/main?svg=true)](https://ci.appveyor.com/project/ashleyfrieze/system-stubs/branch/main)\n [![codecov](https://codecov.io/gh/webcompere/system-stubs/branch/main/graph/badge.svg?token=J0N9VCXFQ1)](https://codecov.io/gh/webcompere/system-stubs)\n[![Maven Central Version](https://img.shields.io/maven-central/v/uk.org.webcompere/system-stubs-parent)](https://central.sonatype.com/namespace/uk.org.webcompere)\n![GitHub Release](https://img.shields.io/github/v/release/webcompere/system-stubs)\n![Java](https://img.shields.io/badge/java-11-white.svg)\n\n\u003e **⚠ WARNING: JDK Compatibility.**\n\u003e From JDK16 onwards, there are deeper restrictions on the ability to use reflection. Previous versions of this library, and others in the space, encounter\n\u003e an Illegal Reflective Access warning, or even a runtime error such as `java.lang.reflect.InaccessibleObjectException` when trying to manipulate\n\u003e the `Map` behind the system's environment variables.\n\u003e\n\u003e Consequently, this library now uses `bytebuddy` to enable\n\u003e the interception of calls for reading environment variables. This might interact with your\n\u003e chosen version of Mockito or other libraries.\n\u003e\n\u003e **⚠ WARNING: JDK Support.**\n\u003e _This project has now moved to a JDK11 minimum version_\n\u003e\n\u003e The v2.x branch is the LTS version. However, there is best effort support to keep the Java 8 compatible\n\u003e [v1.x](https://github.com/webcompere/system-stubs/tree/1.x) branch.\n\n## Overview\nSystem Stubs is used to test code which depends on methods in `java.lang.System`.\n\nThe core is test framework agnostic, but there's explicit support for JUnit 4, JUnit 5 and TestNG in\nspecialist sub-modules.\n\nIt is published under the [MIT license](http://opensource.org/licenses/MIT) and requires at least Java 11.\nThere is a [walkthrough of its main features](https://www.baeldung.com/java-system-stubs) over on\n[Baeldung.com](https://www.baeldung.com).\n\nSystem Stubs [originated](History.md) as a fork of System Lambda, and is a partial rewrite and refactor of it.\nIt has diverged in implementation from the original, but largely [retains compatibility](History.md#execute-around).\n\nIt is divided into:\n\n- `system-stubs-core` - can be used stand-alone with any test framework to stub system resources around test code\n  - Using the `SystemStubs` facade to build and execute stubs around test code\n  - Using the subclasses of `TestResource`, like `EnvironmentVariables` or `SystemIn` to create stubs\n  and then execute test code via `execute`\n- [`system-stubs-junit4`](system-stubs-junit4/README.md) - a set of JUnit4 rules that activate the stubs around test code\n- [`system-stubs-jupiter`](system-stubs-jupiter/README.md) - a JUnit 5 extension that automatically injects\nSystem Stubs into JUnit 5 tests.\n- [`system-stubs-testng`](system-stubs-testng/README.md) - a plugin/listener for the TestNG framework, which automatically\ninjects System Stubs into TestNG tests.\n\n\n## QuickStart (JUnit 5)\n\n```java\n@ExtendWith(SystemStubsExtension.class)\nclass WithEnvironmentVariables {\n\n    @SystemStub\n    private EnvironmentVariables variables =\n        new EnvironmentVariables(\"input\", \"foo\");\n\n    @Test\n    void hasAccessToEnvironmentVariables() {\n        assertThat(System.getenv(\"input\"))\n            .isEqualTo(\"foo\");\n    }\n\n    @Test\n    void changeEnvironmentVariablesDuringTest() {\n        variables.set(\"input\", \"bar\");\n\n        assertThat(System.getenv(\"input\"))\n            .isEqualTo(\"bar\");\n    }\n}\n```\n\n## Installation\n\n### Core\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.org.webcompere\u003c/groupId\u003e\n  \u003cartifactId\u003esystem-stubs-core\u003c/artifactId\u003e\n  \u003cversion\u003e2.1.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### JUnit 4 Plugin\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.org.webcompere\u003c/groupId\u003e\n  \u003cartifactId\u003esystem-stubs-junit4\u003c/artifactId\u003e\n  \u003cversion\u003e2.1.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### JUnit 5 Extension\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.org.webcompere\u003c/groupId\u003e\n  \u003cartifactId\u003esystem-stubs-jupiter\u003c/artifactId\u003e\n  \u003cversion\u003e2.1.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### TestNG Plugin\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003euk.org.webcompere\u003c/groupId\u003e\n  \u003cartifactId\u003esystem-stubs-testng\u003c/artifactId\u003e\n  \u003cversion\u003e2.1.8\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nSee the full guide to [JUnit 5](system-stubs-jupiter/README.md), or use it with [JUnit 4](system-stubs-junit4/README.md).\n\n## Catalogue of SystemStubs Objects\n\n- `EnvironmentVariables` - for overriding the environment variables\n- `SystemProperties` - for temporarily overwriting system properties and then restoring them afterwards\n- `SystemOut` - for tapping the output to `System.out`\n- `SystemErr` - for tapping the output to `System.err`\n- `SystemErrAndOut` - for tapping the output to both `System.err` and `System.out`\n- `SystemIn` - for providing input to `System.in`\n- `SystemExit` - prevents system exit from occurring, recording the exit code\n\n## Using System Stubs Individually\n\nThe plugins for JUnit etc will allow the stub objects to be used during a test, where they will\nbe set up and torn down around the test method. However, they can also be used without the framework.\n\nYou can declare a system stub object:\n\n```java\nEnvironmentVariables environmentVariables = new EnvironmentVariables(\"a\", \"b\");\n```\n\nThen you can configure it and execute your test code inside it:\n\n```java\nenvironmentVariables.set(\"c\", \"d\")\n    .execute(() -\u003e { ... some test code that gets the environment variables ... });\n```\n\nWhere necessary, each of the System Stub objects can be manually activated with `setup`\nand turned off again with `teardown`. Where possible, these objects also support\nreconfiguration while they're active, allowing you to set environment variables within\na test, for example:\n\n```java\nEnvironmentVariables env = new EnvironmentVariables(\"HOST\", \"localhost\");\n\n// start controlling the environment\nenv.setup();\n\n// the HOST variable is currently set\n\nenv.set(\"a\", \"b\");\n// this has set \"a\" as \"b\" in the environment\n\n// tidy up\nenv.teardown();\n```\n\nIt should not be necessary to use `setup` and `teardown` as the `execute` method handles this more cleanly, avoiding accidentally leaving the stubbing active:\n\n```java\nnew EnvironmentVariables(\"HOST\", \"localhost\")\n  .execute(() -\u003e {\n     // in here the environment is temporarily set\n  });\n\n// out here everything has been tidied away\n```\n\n**Note:** there are two versions of the `execute` method in `Executable` allowing\nthe test code to return values, or not.\n\n### Using multiple stubs\n\nWhile you can set up stubs inside the `execute` method of a parent stub:\n\n```java\nnew EnvironmentVariables(\"a\", \"b\")\n    .execute(() -\u003e {\n        new SystemProperties(\"j\", \"k\")\n            .execute(() -\u003e { ... has env and properties ... });\n    });\n```\n\nThere is a more convenient way to use multiple stubs together:\n\n```java\nEnvironmentVariables env = new EnvironmentVariables(\"a\", \"b\");\nSystemProperties props = new SystemProperties(\"f\", \"g\");\nResources.execute(() -\u003e { .. some test code .. },\n    env, props);\n```\n\nThe convenience method `Resource.with` may make this read more cleanly:\n\n```java\nwith(new EnvironmentVariables(\"HTTP_PROXY\", \"\"),\n    new SystemProperties(\"http.connections\", \"123\"))\n    .execute(() -\u003e executeTestCode());\n```\n\n**Note:** the JUnit4 and JUnit5 plugins make it easier to use multiple test stubs, as they set all the stubs up before the test method and then tidy them up at the end.\n\n## Exception Handling\n\nAs the `execute` methods can be used with code that throws exceptions, they\ndeclare `throws Exception` so your tests need to declare `throws Exception`, even if\nthe code under the test doesn't use checked exceptions.\n\nThis is a good argument for using the JUnit4 or JUnit5 plugins, where you do not\nneed to specifically turn the stubbing on via the `execute` method.\n\n## How to Use Each of the Stubs\n\n### System.exit\n\nCommand-line applications terminate by calling `System.exit` with some status\ncode. If you test such an application then the JVM that executes the test exits\nwhen the application under test calls `System.exit`.\n\n#### With `SystemStubs`\n\nThe method `catchSystemExit` returns the status code of the\n`System.exit` call rather than ending the JVM\n\n```java\n@Test\nvoid application_exits_with_status_42() throws Exception {\n  int statusCode = catchSystemExit(() -\u003e {\n    System.exit(42);\n  });\n  assertEquals(42, statusCode);\n}\n```\n\nThe method `catchSystemExit` throws an `AssertionError` if the code under test\ndoes not call `System.exit`. Therefore your test fails with the failure message\n\"System.exit has not been called.\"\n\n#### `SystemExit` Class\n\nThe `SystemExit` class can be used just to ignore a System exit:\n\n```java\nnew SystemExit()\n    .execute(() -\u003e {\n        System.exit(0);\n    });\n\n// execution continues without error\n```\n\nOr an instance can be used to capture the return code, or whether there was an\nexit at all.\n\n```java\nSystemExit exit = new SystemExit();\nexit.execute(() -\u003e {\n        System.exit(0);\n    });\n\nassertThat(exit.getExitCode()).isEqualTo(0);\n\n// the exit code will be `null` if no System.exit was called\n```\n\n### Environment Variables\n\n#### With `SystemStubs`\n\nThe method `withEnvironmentVariable` allows you to set environment variables\nwithin your test code that are removed after your code under test is executed.\n\n```java\n@Test\nvoid execute_code_with_environment_variables() throws Exception {\n  List\u003cString\u003e values = withEnvironmentVariable(\"first\", \"first value\")\n    .and(\"second\", \"second value\")\n    .execute(() -\u003e asList(\n      System.getenv(\"first\"),\n      System.getenv(\"second\")\n    ));\n  assertEquals(asList(\"first value\", \"second value\"), values);\n}\n```\n\n#### With `EnvironmentVariables`\n\nCreate an object of `EnvironmentVariables` and use `execute`:\n\n```java\nList\u003cString\u003e values = new EnvironmentVariables(\"first\", \"first value\")\n    .set(\"second\", \"second value\")\n    .execute(() -\u003e asList(\n         System.getenv(\"first\"),\n         System.getenv(\"second\")\n       ));\n     assertEquals(asList(\"first value\", \"second value\"), values);\n```\n\n**Note:** the `SystemStubs` facade creates an identical object and `set` is a\nmutable version of the `and` method used in the first example.\n\n**Note:** calling `set` on `EnvironmentVariables` from inside `execute` will\naffect the runtime environment. Calling it outside of execution will store the\nvalue for writing into the environment within `execute`.\n\nYou can remove an environment variable with `remove`:\n\n```java\n// assuming that there's an environment variable \"STAGE\" set here\nnew EnvironmentVariables()\n    .remove(\"STAGE\")\n    .execute(() -\u003e {\n        // the variable has been removed\n        assertThat(System.getenv(\"STAGE\")).isNull();\n    });\n```\n\nThe `remove` method deletes environment variables requested in the `EnvironmentVariables` object previously\nand also takes those environment variables out of the system environment while the `EnvironmentVariables`\nobject is active.\n\n### System Properties\n\n#### With `SystemStubs`\n\nThe method `restoreSystemProperties` guarantees that after executing the test\ncode each System property has the same value as before. Therefore you can\nmodify System properties inside of the test code without having an impact on\nother tests.\n\n```java\n@Test\nvoid execute_code_that_manipulates_system_properties() throws Exception {\n  restoreSystemProperties(() -\u003e {\n    System.setProperty(\"some.property\", \"some value\");\n    //code under test that reads properties (e.g. \"some.property\") or\n    //modifies them.\n  });\n\n  //Here the value of \"some.property\" is the same like before.\n  //E.g. it is not set.\n}\n```\n\nThis also supports removing properties from the system properties:\n\n```java\n// will be restored\nrestoreSystemProperties(() -\u003e{\n  System.getProperties().remove(\"someProp\");\n});\n```\n\n#### With `SystemProperties`\n\nA `SystemProperties` object allows you to set the system properties that will be provided\nwithin `execute`. It provides a `set` method which writes to the System while the\nobject is _active_, though any other set operations that are performed with\n`System.setProperty` are also reset on clean up:\n\n```java\nSystemProperties someProperties = new SystemProperties(\n    \"foo\", \"bar\",\n    \"foz\", \"boz\");\nsomeProperties.execute(() -\u003e {\n    // here we expect the properties to have been set\n\n    // we can also call \"set\" on the \"someProperties\"\n    // to set more system properties - these will be\n    // remembered for reuse later with that object\n\n    // any calls to System.setProperty will be undone when\n    // \"execute\" is finished\n});\n\n// here the system properties are reverted\n```\n\nWe can also specify properties to delete from the default system properties:\n\n```java\n// when this object is active, some properties will be removed\n// from system properties\nSystemProperties someProperties = new SystemProperties()\n    .remove(\"property1\")\n    .remove(\"property2\");\n```\n\n### Sources of `Properties` for `EnvironmentVariables` and `SystemProperties`\n\nOnce you have constructed an `EnvironmentVariables` or `SystemProperties` object, you can use the `set` method to apply properties. If these objects are presently _active_\nthen the values are applied to the running environment immediately, otherwise they\nare kept until the object is activated either by `execute` or within the JUnit test\nlifecycle, as part of the JUnit 4 or JUnit 5 plugins.\n\nThere is a `set` function for name/value pairs, and also a `set` function that\ntakes `Map\u003cObject, Object\u003e`, which is the base class of `Properties`. There are helper\nfunctions within `PropertySource` for loading `Properties` from file or resources.\n\nSo you can initialise one of these stubs from a resource:\n\n```java\n// Note, we have statically imported `PropertySource.fromResource`\nEnvironmentVariables env = new EnvironmentVariables()\n    .set(fromResource(\"test.properties\"))\n    .execute(() -\u003e {... test code });\n```\n\nOr from a file:\n\n```java\nSystemProperties props = new SystemProperties();\nprops.execute(() -\u003e {\n    // do something\n\n    // now set the system properties from a file\n    props.set(fromFile(\"src/test/resources/test.properties\"));\n});\n```\n\nOr from a map:\n\n```java\n// Map.of is available in later Java versions\n// ImmutableMap.of from Guava is a similar alternative\nEnvironmentVariables env = new EnvironmentVariables();\nenv.execute(() -\u003e {\n    // do something\n\n    // now set some environment variables\n    env.set(Map.of(\"VAL\", \"value1\",\n                  \"VAL2\", \"value\"));\n});\n```\n\nThe name/value pair constructors in both `EnvironmentVariables` and `SystemProperties` are probably easier than using `set` with a `Map` where it's possible to use them.\n\nThe `EnvironmentVariables` and `SystemProperties` objects both accept a `Properties` object via their constructor. It's a question of preference whether to use the constructor or set method:\n\n```java\nnew EnvironmentVariables()\n   .set(fromFile(\"somefile\"));\n\n// vs\n\nnew EnvironmentVariables(fromFile(\"someFile\"));\n```\n\nIf you have the properties to set in memory already as a series of `String` objects in the `name=value` format used by properties files, you can use `LinesAltStream` to provide them to the property loader as an `InputStream`:\n\n```java\nEnvironmentVariables env = new EnvironmentVariables()\n   .set(fromInputStream(new LinesAltStream(\"PROXY_HOSTS=foo.bar.com\")))\n   .execute(() -\u003e {\n      // the PROXY_HOSTS environment variable is set here\n   });\n```\n\n### Stubbing `System.out` and `System.err`\n\n#### With `SystemStubs`\n\nCommand-line applications usually write to the console. If you write such\napplications you need to test the output of these applications. The methods\n`tapSystemErr`, `tapSystemErrNormalized`, `tapSystemOut` and\n`tapSystemOutNormalized` and `tapSystemErrAndOut` allow you to tap the text that is written to\n`System.err`/`System.out`. The methods with the suffix `Normalized` normalize\nline breaks to `\\n` so that you can run tests with the same assertions on\ndifferent operating systems.\n\n```java\n@Test\nvoid application_writes_text_to_System_err() throws Exception {\n  String text = tapSystemErr(() -\u003e {\n    System.err.print(\"some text\");\n  });\n  assertEquals(\"some text\", text);\n}\n\n@Test\nvoid application_writes_mutliple_lines_to_System_err() throws Exception {\n  String text = tapSystemErrNormalized(() -\u003e {\n    System.err.println(\"first line\");\n    System.err.println(\"second line\");\n  });\n  assertEquals(\"first line\\nsecond line\\n\", text);\n}\n\n@Test\nvoid application_writes_text_to_System_out() throws Exception {\n  String text = tapSystemOut(() -\u003e {\n    System.out.print(\"some text\");\n  });\n  assertEquals(\"some text\", text);\n}\n\n@Test\nvoid application_writes_multiple_lines_to_System_out() throws Exception {\n  String text = tapSystemOutNormalized(() -\u003e {\n    System.out.println(\"first line\");\n    System.out.println(\"second line\");\n  });\n  assertEquals(\"first line\\nsecond line\\n\", text);\n}\n```\n\n`System.err` and `System.out` can be directed to a single stream:\n\n```java\n@Test\nvoid application_writes_text_to_System_err_and_out() throws Exception {\n  String text = tapSystemErrAndOut(() -\u003e {\n    System.err.print(\"text from err\");\n    System.out.print(\"text from out\");\n  });\n  assertEquals(\"text from errtext from out\", text);\n}\n```\n\nYou can assert that nothing is written to `System.err`/`System.out` by wrapping\ncode with the function\n`assertNothingWrittenToSystemErr`/`assertNothingWrittenToSystemOut`. E.g. the\nfollowing tests fail:\n\n```java\n@Test\nvoid fails_because_something_is_written_to_System_err() throws Exception {\n  assertNothingWrittenToSystemErr(() -\u003e {\n    System.err.println(\"some text\");\n  });\n}\n\n@Test\nvoid fails_because_something_is_written_to_System_out() throws Exception {\n  assertNothingWrittenToSystemOut(() -\u003e {\n    System.out.println(\"some text\");\n  });\n}\n```\n\nIf the code under test writes text to `System.err`/`System.out` then it is\nintermixed with the output of your build tool. Therefore you may want to avoid\nthat the code under test writes to `System.err`/`System.out`. You can achieve\nthis with the function `muteSystemErr`/`muteSystemOut`. E.g. the following tests\ndon't write anything to `System.err`/`System.out`:\n\n```java\n@Test\nvoid nothing_is_written_to_System_err() throws Exception {\n  muteSystemErr(() -\u003e {\n    System.err.println(\"some text\");\n  });\n}\n\n@Test\nvoid nothing_is_written_to_System_out() throws Exception {\n  muteSystemOut(() -\u003e {\n    System.out.println(\"some text\");\n  });\n}\n```\n\n#### Using `SystemErr`, `SystemOut` and `SystemErrAndOut`\n\nThe methods on the facade provide some useful shortcuts, but there are also\nthe classes `SystemOut` and `SystemErr` which can be used independently.\n\n##### Providing a Single Output Target\n\nWhen creating a `SystemOut` object, its constructor can be passed the relevant `Output` types of `NoopStream`, `DisallowWriteStream` or `TapStream`. The default is `TapStream`.\n\nOnce output has been captured, all of the objects provide functions for getting the text\nthat arrived at the stream, sliced into lines or whole.\n\nYou can plug in an alternative output by implementing your own `Output` subclass.\n\n**Note:** The `DisallowWriteStream` cannot capture text as any writes stop the text with an error.\nThe `NoopStream` does not capture text, so it useful for saving memory/log files during a test.\n\nExample:\n\n```java\nSystemOut systemOut = new SystemOut();\nsystemOut.execute(() -\u003e System.out.print(\"hello world\"));\nassertThat(systemOut.getText()).isEqualTo(\"hello world\");\n```\n\nThe objects can be reused and have a `clear` function to clear captured text between usages.\n\n**Note:** As the `SystemOut`, `SystemErr` and `SystemErrAndOut` classes are also derived from `Output`, they have friendlier methods on them for reading the text that was sent to the output. E.g. `getLines`\nwhich returns a stream of lines, separated from the text captured by the system line separator.\n\n**Note:** The `withSystemErrAndOut` method on the facade constructs a `SystemErrAndOut` object for use with the `execute` method and for assertion via `getLines` or `getText`:\n\n```java\n// finer control over assertion can be made using the SystemErrAndOut object\n@Test\nvoid construct_system_err_and_out_tap() throws Exception {\n    SystemErrAndOut stream = withSystemErrAndOut(new TapStream());\n    stream.execute(() -\u003e {\n        System.err.println(\"text from err\");\n        System.out.println(\"text from out\");\n    });\n    assertThat(stream.getLines())\n        .containsExactly(\"text from err\",\"text from out\");\n}\n```\n\n##### Multiple Outputs - Tapping `System.out` in Combinations\n\nOne of the advantages of tapping the `System.out` and `System.err` streams is that the tests can assert what was output. However, seeing the output of the application during the test can also be helpful for debugging.\n\nThere is an alternative way to provide the `Output` object for the `SystemOut`, `SystemErr` and `SystemErrAndOut` objects to use. If you pass an `OutputFactory` then this can be used to construct the final `Output` object using the original `OutputStream` that was being used before the stubbing started. This allows the output to reuse the original console `PrintStream` alongside any other streams.\n\nThere is also a `MultiplexOutput` class which is able to direct the output to more than one `Output` object. **Note:** the first `Output` will be the default used for `getText` and related operations. Though if you created and stored references to all of the `Output` objects in the multiplex, you can interact with them directly.\n\nThough the lower level classes may be useful for building custom configurations, the most common options are within the `OutputFactories` class.\n\nFor example, you can both capture `System.out` and allow it to continue writing to the console like this:\n\n```java\nSystemOut systemOut = new SystemOut(tapAndOutput());\nsystemOut.execute(() -\u003e System.out.println(\"I write to the console and the tap\"));\nassertThat(systemOut.getLines()).containsExactly(\"I write to the console and the tap\");\n```\n\nThe `tapAndOutput` function produces a multiplex of both `TapStream` and writing to the original stream.\n\nWhen using the `execute` method (as above), rather than any of the JUnit plugins, it's also possible to capture the output to a file using `writeToFile` as the `OutputFactory`:\n\n```java\nFile target = new File(tempDir, \"file\");\nnew SystemOut(ofMultiplePlusOriginal(writeToFile(target)))\n  .execute(() -\u003e {\n    System.out.println(\"This is going into a file\");\n  });\n\nassertThat(target).hasContent(\"This is going into a file\" + System.lineSeparator());\n```\n\nWhile the file output does not depend itself on the original stream, it hooks its creation and closure of the `OutputStream` into the lifecycle of the execute method.\n\nTechnically this could also be used with the JUnit plugins, but the written file could not be accessed within the test that it logged.\n\nThe `OutputFactories` class provides various methods for adding together multiple `Output` objects. The `Output.fromStream` and `Output.fromCloseableStream` methods provide `Output` wrappers of your own `OutputStream` objects.\n\n**Note:** you can compose multiple `Output` objects or multiple `OutputFactory` objects. If you have a mixture, then convert the `Output` objects into `OutputFactory` objects using `Output.factoryOfSelf`.\n\nThere are some worked examples in the [tests of `OutputFactories`](system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/output/OutputFactoriesTest.java).\n\n##### Asserting Log Output\n\nThe `SystemOut` stub allows logging output to be captured in situations where the logging framework is configured to write to the console.\n\nLet's say the code under test contained this line:\n\n```java\nLOGGER.info(\"Saving to database\");\n```\n\nWe could imagine testing that with a `SystemOut` object:\n\n```java\nSystemOut systemOut = new SystemOut();\n\n// then either in the execute method, or via JUnit4 or JUnit5 integration\n\nrealCode.doThingThatLogs();\nassertThat(systemOut.getLines())\n  .anyMatch(line -\u003e line.contains(\"Saving to database\"));\n```\n\n### Stubbing `System.in`\n\nInteractive command-line applications read from `System.in`. You can\nsupply the application with input at test time as lines of text, delimited by\nthe system line separator, or by hooking `System.in` up to a\nspecific `InputStream`.\n\n#### With `SystemStubs`\n\nYou can specify\nthe lines that are available from `System.in` with the method\n`withTextFromSystemIn`\n\n```java\n@Test\nvoid Scanner_reads_text_from_System_in() throws Exception {\n  withTextFromSystemIn(\"first line\", \"second line\")\n    .execute(() -\u003e {\n      Scanner scanner = new Scanner(System.in);\n      assertEquals(\"first line\", scanner.nextLine());\n      assertEquals(\"second line\", scanner.nextLine());\n    });\n}\n```\n\nFor a complete test coverage you may also want to simulate `System.in` throwing\nexceptions when the application reads from it. You can specify such an\nexception (either `RuntimeException` or `IOException`) after specifying the\ntext. The exception will be thrown by the next `read` after the text has been\nconsumed.\n\n```java\n@Test\nvoid System_in_throws_IOException() throws Exception {\n  withTextFromSystemIn(\"first line\", \"second line\")\n    .andExceptionThrownOnInputEnd(new IOException())\n    .execute(() -\u003e {\n      Scanner scanner = new Scanner(System.in);\n      scanner.nextLine();\n      scanner.nextLine();\n      assertThrownBy(\n        IOException.class,\n        () -\u003e scanner.readLine()\n      );\n  });\n}\n\n@Test\nvoid System_in_throws_RuntimeException() throws Exception {\n  withTextFromSystemIn(\"first line\", \"second line\")\n    .andExceptionThrownOnInputEnd(new RuntimeException())\n    .execute(() -\u003e {\n      Scanner scanner = new Scanner(System.in);\n      scanner.nextLine();\n      scanner.nextLine();\n      assertThrownBy(\n        RuntimeException.class,\n        () -\u003e scanner.readLine()\n      );\n    });\n}\n```\n\nYou might also write a test that throws an exception immediately by not providing any\ntext.\n\n```java\nwithTextFromSystemIn()\n  .andExceptionThrownOnInputEnd(...)\n  .execute(() -\u003e {\n    Scanner scanner = new Scanner(System.in);\n    assertThrownBy(\n      ...,\n      () -\u003e scanner.readLine()\n    );\n  });\n```\n\nThe `SystemStubs` implementation only allows you to specify\ntext for stubbing `System.in`, the `SystemIn` object is more\nconfigurable.\n\n#### `SystemIn` and `AltInputStream`\n\nThe `SystemIn` object allows you to compose your own input text. You can\nuse it with any `InputStream`.\n\nE.g.\n\n```java\nSystemIn systemIn = new SystemIn(new FileInputStream(\"someTestFile\"));\nsystemIn.execute(() -\u003e {\n    // code that uses System.in\n});\n```\n\nThe `SystemIn` object can be manipulated to throw an exception\nwhen the calling code reads from `System.in` when it has run out of text:\n\n```java\nnew SystemIn(\"some text in the input\")\n   .andExceptionThrownOnInputEnd(new IOException(\"file is broken\"))\n   .execute(() -\u003e {\n      // some test code\n   });\n```\n\n`SystemIn` can be constructed with lines of text,\nor any instance of `AltStream` or `InputStream` you wish to create.\n\nThe lines of input are automatically separated by the system line separator\nvia the `LinesAltStream` object. But the alternative `TextAltStream` can be used\nwhere the input is already formatted and should not have an extra line breaks added.\n\nWhile hardcoded lists of strings are often perfect sources of test\ndata, `LinesAltStream` also allows for more custom use cases, for example,\n`SystemIn` could be hooked up to a random input generator:\n\n```java\nnew SystemIn(new LinesAltStream(\n    Stream.generate(() -\u003e UUID.randomUUID().toString())))\n    .execute(() -\u003e {\n        // this test code will be provided with an unlimited\n        // series of lines in System.in containing GUIDs\n    });\n```\n\n### Stubbing `SecurityManager`\n\n#### With `SystemStubs`\n\nThe function `withSecurityManager` lets you specify the `SecurityManager` that\nis returned by `System.getSecurityManger()` while your code under test is\nexecuted.\n\n```java\n@Test\nvoid execute_code_with_specific_SecurityManager() throws Exception {\n  SecurityManager securityManager = new ASecurityManager();\n  withSecurityManager(\n    securityManager,\n    () -\u003e {\n      //code under test\n      //e.g. the following assertion is met\n      assertSame(\n        securityManager,\n        System.getSecurityManager()\n      );\n    }\n  );\n}\n```\n\nAfter `withSecurityManager(...)` is executed`System.getSecurityManager()`\nreturns the original security manager again.\n\n#### With `SecurityManagerStub`\n\nThe `SecurityManagerStub` allows you to substitute the system security manager with\nanother. Provide the alternative manager via the constructor.\n\n```java\nnew SecurityManagerStub(otherManager)\n    .execute(() -\u003e { ... test code ... });\n```\n\nThis is used internally by the stubbing for `System.exit`.\n\n## Thread Safety\n\n**⚠ WARNING: Don't Break Your Parallel Tests!**\n\nIf you are using System Stubs alongside concurrent test execution, then you MUST ensure that\nthe concurrency is achieved by forking multiple JVMs to run different test classes,\nrather than running multiple threads within the same JVMs executing tests in parallel.\n\nThis is because many of the stubs modify global system properties which would bleed to\nother tests in the same JVM runtime and **cannot** be localised to just the current test.\n\nBuild tools allow the test runner to fork separate processes for running subsets of the\ntest classes, and this is the only safe way to use System Stubs with concurrent testing.\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=webcompere/system-stubs\u0026type=date\u0026legend=top-left)](https://www.star-history.com/#webcompere/system-stubs\u0026type=date\u0026legend=top-left)\n\n## Contributing\n\nYou have two options if you have a feature request, found a bug or\nsimply have a question.\n\n* [Write an issue.](https://github.com/webcompere/system-stubs/issues/new)\n* Create a pull request. (See [Understanding the GitHub Flow](https://guides.github.com/introduction/flow/index.html))\n\n## Development Guide\n\nSystem Stubs is built with [Maven](http://maven.apache.org/). **It requires JDK11\nto build**.\n\nIf you want to contribute code then:\n\n* Please write a test for your change.\n* Ensure that you didn't break the build by running `mvnw test`.\n* Fork the repo and create a pull request. (See [Understanding the GitHub Flow](https://guides.github.com/introduction/flow/index.html))\n\nThe basic coding style is described in the\n[EditorConfig](http://editorconfig.org/) file `.editorconfig`.\n\nSystem Stubs is built with Appveyor: [![Build status](https://ci.appveyor.com/api/projects/status/r943gjn189rlxts9?svg=true)](https://ci.appveyor.com/project/ashleyfrieze/system-stubs)\n\n## Release Guide\n\n* Move the snapshot version number if necessary using\n  [Semantic Versioning 2.0.0 Standard](http://semver.org/).\n* With `gpg` installed\n* May need to login to `gpg` to set the passphrase\n* With env variables\n  - `JAVA_HOME` set to JDK11\n  - `GPG_TTY=$(tty)`\n  - `GPG_AGENT_INFO`\n* With the nexus credentials set in the `.m2/settings.xml`\n* Run `mvn clean -Dgpg.executable=gpg -Prelease-sign-artifacts -Dgpg.passphrase=\u003cbiscuit leet\u003e release:prepare release:perform`\n* Update the installation guide in the README\n* Push a new version to the README\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebcompere%2Fsystem-stubs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebcompere%2Fsystem-stubs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebcompere%2Fsystem-stubs/lists"}