Skip to content

A JUnit5 Extension to help write tests that call System.exit()

License

Notifications You must be signed in to change notification settings

tginsberg/junit5-system-exit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JUnit5 System.exit() Extension

This JUnit 5 Extension helps you write tests for code that calls System.exit(). Starting with JUnit 5, @Rules, @ClassRules, and Runners were replaced by the Extension concept.

Installing

Copy the following into your build.gradle or build.xml.

Gradle

testImplementation("com.ginsberg:junit5-system-exit:1.1.2")

Maven

<dependency>
    <groupId>com.ginsberg</groupId>
    <artifactId>junit5-system-exit</artifactId>
    <version>1.1.2</version>
    <scope>test</scope>
</dependency>

Notes On Compatibility With Newer JVMs

Starting with Java 17, the use of the SecurityManager class (see details of its use) is deprecated and will emit a warning. This is a known issue and once an alternative is available, I will explore the possibility of upgrading this library.

Starting with Java 18, the default behavior of the JVM was changed from allowing the SecurityManager to be changed at runtime to disallowing it by default. To re-enable the pre-Java 18 behavior, set the system property java.security.manager to the string allow. The details can be read here if you are interested.

So, for Gradle:

test {
    systemProperty 'java.security.manager', 'allow'
}

And for Maven:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <systemPropertyVariables>
            <java.security.manager>allow</java.security.manager>
        </systemPropertyVariables>
    </configuration>
</plugin>

Why doesn't junit5-system-exit set this property for me?

Good question, it certainly could! However, given the decision to terminally deprecate the SecurityManager, overriding this decision in a way that is not completely obvious to the people using is not something I want to do. I feel that users should make a conscious positive decision to override this behavior and take the time to evaluate the needs of their project. I don't want somebody caught by surprise that the SecurityManager is behaving in a non-default way because they happen to be using a testing library.

Use cases

A Test that expects System.exit() to be called, with any status code:

public class MyTestCases { 
    
    @Test
    @ExpectSystemExit
    public void thatSystemExitIsCalled() {
        System.exit(1);
    }
}

A Test that expects System.exit(1) to be called, with a specific status code:

public class MyTestCases {
    
    @Test
    @ExpectSystemExitWithStatus(1)
    public void thatSystemExitIsCalled() {
        System.exit(1);
    }
}

A Test that should not expect System.exit(1) to be called, and fails the test if it does:

public class MyTestCases {
    
    @Test
    @FailOnSystemExit
    public void thisTestWillFail() {
        System.exit(1);
    }
}

The @ExpectSystemExit, @ExpectSystemExitWithStatus, and @FailOnSystemExit annotations can be applied to methods, classes, or annotations (to act as meta-annotations).

Contributing and Issues

Please feel free to file issues for change requests or bugs. If you would like to contribute new functionality, please contact me first!

Copyright © 2021-2024 by Todd Ginsberg