org.hyphenType.unittesting
Class NonExceptionalExit
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
org.hyphenType.unittesting.NonExceptionalExit
- All Implemented Interfaces:
- Serializable
public final class NonExceptionalExit
- extends RuntimeException
A (strange) exception that is thrown to simulate JVM exit when we utilize
MockArgumentsInvocationHandler
. Behind the scenes, the
MockArgumentsInvocationHandler
will utilize a
UnitTestingOptionExtractor
, which in turn is responsible for throwing
exceptions of type NonExceptionalExit
. There are cases in which
programmers may chose to design their algorithms under the assumption that a
call to methods Options#exit(Enum)
or Options#exit(int)
will
prevent subsequent code to be executed. This is the case, for instance, in
the following code:
public static int x(Opt opt) {
if (!opt.a())
opt.exit(17);
return 12;
}
Assume that opt.a()
returns true
. In such case, execution of
the method x(Opt opt)
should never reach the return
statement, even when we execute this method during unit testing. Not
suspending the execution of the method x(Opt opt)
when we reach the
statement opt.exit(1)
may cause the behavior of the code under test
to change during unit testing. To prevent such behavior change, this
exception ( NonExceptionalExit
) is silently thrown every time to
methods Options#exit(Enum)
or Options#exit(int)
are called.
Since NonExceptionalExit
is a RuntimeException
, procedures
that call Options#exit(Enum)
or Options#exit(int)
directly do
not need to catch the exception for the source code to compile. Note that
there is no exception handling in the method x(Opt opt)
above. On the
other hand, unit tests that cause the execution of methods such as x(Opt opt)
above will need to catch this exception. This is demonstrated in
the following code:
@Test
public void testX() {
UnitTestingOptionExtractor unitTestingOptionExtractor = new UnitTestingOptionExtractor(Opt.class);
Opt opt = oe.options("-b");
try {
x(opt); // Calling x(Opt opt) as defined above
assertFail("We should not reach this line.");
}
catch(NonExceptionalExit e) {
assertTrue(unitTestingOptionExtractor.exitIntCalled(opt));
}
}
In short, throwing this exception does not mean a failure (that's why this
exception is called NonExceptionalExit
), but is only a means to
interrupt execution of a procedure under test. To prevent
UnitTestingOptionExtractor
to throw this exception (strictly
speaking, to prevent MockArgumentsInvocationHandler
to throw this
exception), use the constructor
UnitTestingOptionExtractor.UnitTestingOptionExtractor(Class, boolean)
and pass false
as the second argument.
This class also provides the following methods to check how
Options#exit(int)
or Options#exit(Enum)
was called, and which
of them was called:
Those methods are equivalent to:
Here is an example on how to use those methods in unit testing:
@Test
public void testX() {
UnitTestingOptionExtractor unitTestingOptionExtractor = new UnitTestingOptionExtractor(Opt.class);
Opt opt = oe.options("-b");
try {
x(opt); // Calling x(Opt opt) as defined above
assertFail("We should not reach this line.");
}
catch(NonExceptionalExit e) {
assertTrue(e.exitIntCalled());
assertEquals(17, getStatusCodeInt());
}
}
Additionally, the method exitCallPoint()
can be
used to find in which class, file, and line is the statement that called
Options#exit(Enum)
or Options#exit(int)
:
@Test
public void sample1() throws InvalidOptionsInterfaceException, InvalidOptionException {
UnitTestingOptionExtractor optionExtractor = new UnitTestingOptionExtractor(AnotherOptions.class);
try {
AnotherApplication.main(optionExtractor.options("-x"));
fail("Should have thrown an exception on the line above.");
}
catch (NonExceptionalExit e) {
assertEquals(AnotherApplication.class.getName(), e.exitCallPoint().getClassName());
// Line number detection won't work unless classes were compiled using debug mode.
assertEquals(6, e.exitCallPoint().getLineNumber());
assertEquals("main", e.exitCallPoint().getMethodName());
}
}
The return type of exitCallPoint()
is
StackTraceElement
, which is obtained via
Throwable.getStackTrace()
. Therefore, the stack trace element
returned by exitCallPoint()
will only have the
line number data if the classes were compiled using debug mode. If classes
were not compiled with debug mode, the standard behavior is that those line
numbers will be all set to -1.
- Author:
- Aurelio Akira M. Matsui
- See Also:
UnitTestingOptionExtractor
,
MockArgumentsInvocationHandler
,
Options#exit(Enum)
,
Options#exit(int)
,
Serialized Form
Methods inherited from class java.lang.Throwable |
fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString |
getStatusCodeEnum
public Enum<?> getStatusCodeEnum()
exitEnumCalled
public boolean exitEnumCalled()
getStatusCodeInt
public int getStatusCodeInt()
exitIntCalled
public boolean exitIntCalled()
exitCallPoint
public StackTraceElement exitCallPoint()
Copyright © 2013. All Rights Reserved.