I've got a few methods that should call System.exit()
on certain inputs. Unfortunately, testing these cases causes JUnit to terminate! Putting the method calls in a new Thread doesn't seem to help, since System.exit()
terminates the JVM, not just the current thread. Are there any common patterns for dealing with this? For example, can I subsitute a stub for System.exit()
?
[EDIT] The class in question is actually a command-line tool which I'm attempting to test inside JUnit. Maybe JUnit is simply not the right tool for the job? Suggestions for complementary regression testing tools are welcome (preferably something that integrates well with JUnit and EclEmma).
You can use the java SecurityManager to prevent the current thread from shutting down the Java VM. The following code should do what you want:
One trick we used in our code base was to have the call to System.exit() be encapsulated in a Runnable impl, which the method in question used by default. To unit test, we set a different mock Runnable. Something like this:
...and the JUnit test method...
There is a minor problem with the
SecurityManager
solution. Some methods, such asJFrame.exitOnClose
, also callSecurityManager.checkExit
. In my application, I didn't want that call to fail, so I usedThe library System Rules has a JUnit rule called ExpectedSystemExit. With this rule you are able to test code, that calls System.exit(...):
Full disclosure: I'm the author of that library.
I like some of the answers already given but I wanted to demonstrate a different technique that is often useful when getting legacy code under test. Given code like:
You can do a safe refactoring to create a method that wraps the System.exit call:
Then you can create a fake for your test that overrides exit:
This is a generic technique for substituting behavior for test cases, and I use it all the time when refactoring legacy code. It not usually where I'm going to leave thing, but an intermediate step to get the existing code under test.
How about injecting an "ExitManager" into this Methods:
The production code uses the ExitManagerImpl and the test code uses ExitManagerMock and can check if exit() was called and with which exit code.