Assume we need to write a test for the following simple method. (Yep, I just made this one up.)
public void inconceivable() {
System.exit(42);
}
I can not just call the method in a JUnit test like this (but feel free to try it :-)).
@Test
public void shouldCallSystemExit() {
new ObjectUnderTest().inconceivable();
// Assert what now?
}
One way to make it possible is by utilizing a SecurityManager. By installing a custom security manager I can prevent the exit from actually happen. The following implementation overrides
checkExit()
to throw an exception whenever a call to System.exit() is made. By also overriding checkPermission()
to do nothing, I allow myself to remove the security manager again, after it has been installed.
class ExceptionOnExitSecurityManager extends SecurityManager {
@Override
public void checkExit(int status) {
super.checkExit(status);
throw new SystemExitException(status);
}
@Override
public void checkPermission(Permission perm) {
// Override to allow removal of this security manager
}
}
A custom exception makes it really easy to access the status code.
class SystemExitException extends SecurityException {
int statusCode;
SystemExitException(int statusCode) {
this.statusCode = statusCode;
}
}
Now I am ready to write my test.
@Test
public void shouldCallSystemExit() {
System.setSecurityManager(new ExceptionOnExitSecurityManager());
try {
new ObjectUnderTest().inconceivable();
fail("Did not call System.exit()");
} catch (SystemExitException e) {
assertEquals(42, e.statusCode);
}
System.setSecurityManager(null);
}
This test will fail nicely if System.exit() is never called, or if it is called with a different status code than expected. Now the expected behaviour is documented and verified, and my test coverage moved up a notch.
Do you have a different strategy for this type of situations, or do you see any problems with this approach? Please share it in the comments!
No comments:
Post a Comment