Skip to content

Commit bab4e53

Browse files
authored
Merge pull request #66 from webcompere/test-ng
Add support for TestNG
2 parents fe9775c + ee8b9c9 commit bab4e53

File tree

10 files changed

+530
-28
lines changed

10 files changed

+530
-28
lines changed

README.md

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@
2323
## Overview
2424
System Stubs is used to test code which depends on methods in `java.lang.System`.
2525

26-
It is published under the [MIT license](http://opensource.org/licenses/MIT) and requires at least Java 8. There is a [walkthrough of its main features](https://www.baeldung.com/java-system-stubs) over on [Baeldung.com](https://www.baeldung.com).
26+
The core is test framework agnostic, but there's explicit support for JUnit 4, JUnit 5 and TestNG in
27+
specialist sub-modules.
2728

28-
System Stubs [originated](History.md) as a fork of System Lambda,
29-
originally by Stefan Birkner, and is a partial rewrite and refactor of it. It has diverged in implementation
30-
from the original, but largely [retains compatibility](History.md#execute-around).
29+
It is published under the [MIT license](http://opensource.org/licenses/MIT) and requires at least Java 11.
30+
There is a [walkthrough of its main features](https://www.baeldung.com/java-system-stubs) over on
31+
[Baeldung.com](https://www.baeldung.com).
32+
33+
System Stubs [originated](History.md) as a fork of System Lambda, and is a partial rewrite and refactor of it.
34+
It has diverged in implementation from the original, but largely [retains compatibility](History.md#execute-around).
3135

3236
It is divided into:
3337

@@ -38,6 +42,35 @@ It is divided into:
3842
- [`system-stubs-junit4`](system-stubs-junit4/README.md) - a set of JUnit4 rules that activate the stubs around test code
3943
- [`system-stubs-jupiter`](system-stubs-jupiter/README.md) - a JUnit 5 extension that automatically injects
4044
System Stubs into JUnit 5 tests.
45+
- [`system-stubs-testng`](system-stubs-testng/README.md) - a plugin/listener for the TestNG framework, which automatically
46+
injects System Stubs into TestNG tests.
47+
48+
49+
## QuickStart (JUnit 5)
50+
51+
```java
52+
@ExtendWith(SystemStubsExtension.class)
53+
class WithEnvironmentVariables {
54+
55+
@SystemStub
56+
private EnvironmentVariables variables =
57+
new EnvironmentVariables("input", "foo");
58+
59+
@Test
60+
void hasAccessToEnvironmentVariables() {
61+
assertThat(System.getenv("input"))
62+
.isEqualTo("foo");
63+
}
64+
65+
@Test
66+
void changeEnvironmentVariablesDuringTest() {
67+
variables.set("input", "bar");
68+
69+
assertThat(System.getenv("input"))
70+
.isEqualTo("bar");
71+
}
72+
}
73+
```
4174

4275
## Installation
4376

@@ -71,34 +104,28 @@ System Stubs into JUnit 5 tests.
71104
</dependency>
72105
```
73106

74-
## QuickStart (JUnit 5)
75-
76-
```java
77-
@ExtendWith(SystemStubsExtension.class)
78-
class WithEnvironmentVariables {
79-
80-
@SystemStub
81-
private EnvironmentVariables variables =
82-
new EnvironmentVariables("input", "foo");
107+
### TestNG Plugin
83108

84-
@Test
85-
void hasAccessToEnvironmentVariables() {
86-
assertThat(System.getenv("input"))
87-
.isEqualTo("foo");
88-
}
89-
90-
@Test
91-
void changeEnvironmentVariablesDuringTest() {
92-
variables.set("input", "bar");
93-
94-
assertThat(System.getenv("input"))
95-
.isEqualTo("bar");
96-
}
97-
}
109+
```xml
110+
<dependency>
111+
<groupId>uk.org.webcompere</groupId>
112+
<artifactId>system-stubs-testng</artifactId>
113+
<version>2.1.2</version>
114+
</dependency>
98115
```
99116

100117
See the full guide to [JUnit 5](system-stubs-jupiter/README.md), or use it with [JUnit 4](system-stubs-junit4/README.md).
101118

119+
## Catalogue of SystemStubs Objects
120+
121+
- `EnvironmentVariables` - for overriding the environment variables
122+
- `SystemProperties` - for temporarily overwriting system properties and then restoring them afterwards
123+
- `SystemOut` - for tapping the output to `System.out`
124+
- `SystemErr` - for tapping the output to `System.err`
125+
- `SystemErrAndOut` - for tapping the output to both `System.err` and `System.out`
126+
- `SystemIn` - for providing input to `System.in`
127+
- `SystemExit` - prevents system exit from occurring, recording the exit code
128+
102129
## Using System Stubs Individually
103130

104131
You can declare a system stub object:
@@ -121,6 +148,7 @@ a test, for example:
121148

122149
```java
123150
EnvironmentVariables env = new EnvironmentVariables("HOST", "localhost");
151+
124152
// start controlling the environment
125153
env.setup();
126154

@@ -187,7 +215,7 @@ the code under the test doesn't use checked exceptions.
187215
This is a good argument for using the JUnit4 or JUnit5 plugins, where you do not
188216
need to specifically turn the stubbing on via the `execute` method.
189217

190-
## Available Stubs
218+
## How to Use Each of the Stubs
191219

192220
### System.exit
193221

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<module>system-stubs-core</module>
4141
<module>system-stubs-junit4</module>
4242
<module>system-stubs-jupiter</module>
43+
<module>system-stubs-testng</module>
4344
</modules>
4445

4546
<properties>
@@ -119,6 +120,13 @@
119120
<!-- provided scope - the client provides their own JUnit -->
120121
<scope>provided</scope>
121122
</dependency>
123+
<!-- For TestNG Plugin -->
124+
<dependency>
125+
<groupId>org.testng</groupId>
126+
<artifactId>testng</artifactId>
127+
<version>7.7.0</version>
128+
<scope>provided</scope>
129+
</dependency>
122130
</dependencies>
123131
</dependencyManagement>
124132

system-stubs-testng/README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# System Stubs TestNG
2+
3+
Provides some automatic instantiation of System Stubs objects during the test lifecycle.
4+
5+
```xml
6+
<dependency>
7+
<groupId>uk.org.webcompere</groupId>
8+
<artifactId>system-stubs-testng</artifactId>
9+
<version>2.1.1</version>
10+
</dependency>
11+
```
12+
13+
## Options
14+
15+
### Stub Without the Plugin
16+
System Stubs Core can be used with TestNG as it is framework agnostic.
17+
18+
We can call the `setup` method on any of the stubs in a before method, and `teardown` in the after method.
19+
20+
```java
21+
private EnvironmentVariables environmentVariables = new EnvironmentVariables();
22+
23+
@BeforeTest
24+
public void beforeTest() throws Exception {
25+
environmentVariables.set("setinbefore", "yes");
26+
27+
environmentVariables.setup();
28+
}
29+
30+
@AfterTest
31+
public void afterTest() throws Exception {
32+
environmentVariables.teardown();
33+
}
34+
```
35+
36+
With this code, we'd expect tests to be able to modify the runtime environment by manipulating the
37+
`environmentVariables` object, and we'd expect the tests to have an environment variable `setinbefore` set
38+
to `yes`.
39+
40+
Similarly, we can use `setup` and `teardown` inside a test case, or use the `SystemStubs` methods such as
41+
`withEnvironmentVariables`. See the [main documentation](../README.md) for more on the execute around pattern.
42+
43+
### Using of the Plugin
44+
45+
The plugin:
46+
47+
- Automatically instantiates system stubs objects before they're first used by a TestNG annotated method
48+
- Activates the objects during tests
49+
- Turns the objects off after tests
50+
51+
Usage:
52+
53+
```java
54+
@Listeners(SystemStubsListener.class)
55+
public class CaptureSystemOutTest {
56+
57+
@SystemStub
58+
private SystemOut out;
59+
60+
@BeforeTest
61+
public void beforeTest() {
62+
out.clear();
63+
}
64+
65+
@Test
66+
public void canReadThingsSentToSystemOut() {
67+
// simulate the system under test writing to std out
68+
System.out.println("Can I assert this?");
69+
70+
assertThat(out.getText()).isEqualTo("Can I assert this?\n");
71+
}
72+
}
73+
```
74+
75+
> Note: in this instance we've used the `SystemOut` stub. We've had to remember to call its `clear` method as it
76+
> will be shared between tests.
77+
78+
We can use each of the stubs such as:
79+
80+
- `EnvironmentVariables` - for overriding the environment variables
81+
- `SystemProperties` - for temporarily overwriting system properties and then restoring them afterwards
82+
- `SystemOut` - for tapping the `System.out`
83+
- ... and the others
84+
85+
All we need to do is:
86+
87+
- Add the `@Listeners(SystemStubsListener.class)` annotation to our TestNG test class (using an array with {} if we have other listeners)
88+
- Add a field for each System Stub we want to use
89+
- Annotate that field with the `@SystemStubs` annotation
90+
91+
### Benefits of the Plugin
92+
93+
With the plugin, there's less boilerplate to write. Any exception handling is also covered by the plugin - or at
94+
least, we don't have to explicitly add `throws` to any of our methods that set up or teardown a stub.
95+
96+
However, the plugin is simple and opinionated. For fine-grained control of the stubs, the direct method
97+
may sometimes be preferable.
98+
99+
## Feedback
100+
101+
This TestNG module is incubating. Please raise issues with examples if it proves to have issues in practice.

system-stubs-testng/pom.xml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>uk.org.webcompere</groupId>
9+
<artifactId>system-stubs-parent</artifactId>
10+
<version>2.1.2-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
15+
<artifactId>system-stubs-testng</artifactId>
16+
<version>2.1.2-SNAPSHOT</version>
17+
<packaging>jar</packaging>
18+
19+
<properties>
20+
<maven.compiler.source>11</maven.compiler.source>
21+
<maven.compiler.target>11</maven.compiler.target>
22+
</properties>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>uk.org.webcompere</groupId>
27+
<artifactId>system-stubs-core</artifactId>
28+
</dependency>
29+
30+
<dependency>
31+
<groupId>com.github.spotbugs</groupId>
32+
<artifactId>spotbugs-annotations</artifactId>
33+
</dependency>
34+
35+
<dependency>
36+
<groupId>org.testng</groupId>
37+
<artifactId>testng</artifactId>
38+
<scope>provided</scope>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>org.assertj</groupId>
43+
<artifactId>assertj-core</artifactId>
44+
<scope>test</scope>
45+
</dependency>
46+
</dependencies>
47+
48+
<build>
49+
<plugins>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-surefire-plugin</artifactId>
53+
</plugin>
54+
<plugin>
55+
<groupId>org.jacoco</groupId>
56+
<artifactId>jacoco-maven-plugin</artifactId>
57+
</plugin>
58+
<plugin>
59+
<groupId>org.apache.maven.plugins</groupId>
60+
<artifactId>maven-checkstyle-plugin</artifactId>
61+
</plugin>
62+
<plugin>
63+
<groupId>com.github.spotbugs</groupId>
64+
<artifactId>spotbugs-maven-plugin</artifactId>
65+
</plugin>
66+
67+
<!-- For release -->
68+
<plugin>
69+
<groupId>org.apache.maven.plugins</groupId>
70+
<artifactId>maven-gpg-plugin</artifactId>
71+
</plugin>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-source-plugin</artifactId>
75+
</plugin>
76+
<plugin>
77+
<groupId>org.apache.maven.plugins</groupId>
78+
<artifactId>maven-javadoc-plugin</artifactId>
79+
</plugin>
80+
</plugins>
81+
</build>
82+
83+
</project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package uk.org.webcompere.systemstubs.testng;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
/**
9+
* Marks a field in a test class as a system stub - this causes the {@link SystemStubsListener} to activate
10+
* it during tests. It also causes the field to become instantiated if left uninitialized
11+
* @since 1.0.0
12+
*/
13+
@Target({ ElementType.FIELD })
14+
@Retention(RetentionPolicy.RUNTIME)
15+
public @interface SystemStub {
16+
}

0 commit comments

Comments
 (0)