public class CatchException extends Object
This Javadoc content is also available on the catch-exception web page.
1. How to use catch-exception?
2. What is this stuff actually good for?
3. How does it work internally?
4. When is the caught exception reset?
5. My code throws a ClassCastException. Why?
6. The exception is not caught. Why?
7. Do I have to care about memory leaks?
8. The caught exception is not available in another thread.
Why?
9. How do I catch an exception thrown by a static method?
11. Can I catch errors instead of exceptions?
The most basic usage is:
import static com.googlecode.catchexception.CatchException.*;
// call customerService.prepareBilling(Prize.Zero)
// and catch the exception if any is thrown
catchException(customerService).prepareBilling(Prize.Zero);
// assert that an IllegalArgumentException was thrown
assert caughtException() instanceof IllegalArgumentException;
You can combine the two lines of code in a single one if you like:
There is a minor difference between both variants. In the first variant you
must start the JVM with option // call customerService.prepareBilling(Prize.Zero)
// and throw an ExceptionNotThrownAssertionError if
// the expected exception is not thrown
verifyException(customerService, IllegalArgumentException.class).prepareBilling(Prize.Zero);
-ea
to enable the assertion. The
second variant does not use JDK assertions and ,therefore, always verifies
the caught exception.
A third variant allows you to select the type of exceptions you want to catch
(no verification involved):
// catch IllegalArgumentExceptions but no other exceptions
catchException(customerService, IllegalArgumentException.class).prepareBilling(Prize.Zero);
The fourth and last variant verifies that some exception is thrown, i.e. the
type of the exception does not matter:
verifyException(customerService).prepareBilling(Prize.Zero);
In all variants you can use caughtException()
afterwards to
inspect the caught exception.
Finally, there some alternative ways to catch and verify exceptions:
CatchExceptionBdd
- a BDD-like approach,
CatchExceptionHamcrestMatchers
- Hamcrest assertions
This class targets concise and robust code in tests. Dadid Saff, a commiter to JUnit, has discussed this approach in 2007. Let me summarize the arguments here.
There are two advantages of the approach proposed here in comparison to the use of try/catch blocks.
fail()
behind the method call that is expected to throw an
exception.
There are also some advantages of this approach in comparison to test runner-specific mechanisms that catch and verify exceptions.
The method catchException(obj)
wraps the given object with a
proxy that catches the exception, then (optionally) verifies the exception,
and finally attaches the exception to the current thread for further analysis. The known limitations for proxies apply.
Is both memory consumption and runtime a concern for you? Then use try/catch blocks instead of this class. Because in this case the creation of proxies is an unnecessary overhead. If only either memory consumption or runtime is an issue for you, feel free to configure the cache of the underlying proxy factories as appropriate.
The Method caughtException()
returns the exception thrown by the
last method call on a proxied object in the current thread, i.e. it is reset
by calling a method on the proxied object. If the called method has not
thrown an exception, caughtException()
returns null.
To reset the caught exception manually, call resetCaughtException()
.
At the moment there is no way to reset exceptions that have been caught in
other threads.
Example:
StringBuilder sb = new StringBuilder();
catchException(sb).charAt(-2); // throws ClassCastException
Probably you have tested a final class. Proxy factories usually try to
subclass the type of the proxied object. This is not possible if the original
class is final. But there is a way out. If the tested method belongs to an
interface, then you can cast the argument (here: sb
) to that
interface or ,easier, change the declared type of the argument to the
interface type. This works because the created proxy is not longer required
to have the same type as the original class but it must only have the same
interface.
If the tested
method does no belong to an interface fall back to the try/catch-blocks or
use Powermock
.
// first variant
StringBuilder sb = new StringBuilder();
catchException((CharSequence) sb).charAt(-2); // works fine
// second variant
CharSequence sb = new StringBuilder();
catchException(sb).charAt(-2); // works fine
// example for
PowerMock with JUnit4
@RunWith(PowerMockRunner.class)
@PrepareForTest({ MyFinalType.class })
public class MyTest {
Example:
ServiceImpl impl = new ServiceImpl();
catchException(impl).do(); // do() is a final method that throws an exception
Probably you have tested a final method. If that tested method belongs to an
interface you could use interfaces(Object)
to fix that problem. But
then the syntax starts to become ugly.
I recommend
to use try/catch blocks in such cases.
Service api = new ServiceImpl();
catchException(interfaces(api)).do(); // works fine
This library uses a ThreadLocal
. ThreadLocals are known to cause
memory leaks if they refer to a class the garbage collector would like to
collect. If you use this library only for testing, then memory leaks do not
worry you. If you use this library for other purposes than testing, you
should care.
The caught exception is saved at the thread the exception is thrown in. This is the reason the exception is not visible within any other thread.
Unfortunately, catch-exception does not support this. Fall back on try/catch blocks.
Example:
No,
although the exception is always caught you cannot omit the throws clause in
your test method.
public void testSomething() throws Exception {
...
catchException(obj).do(); // do() throws a checked exception
Yes, have a look at
CatchThrowable
(in module
catch-throwable).
Constructor and Description |
---|
CatchException() |
Modifier and Type | Method and Description |
---|---|
static <T> T |
catchException(T obj)
Use it to catch an exception and to get access to the thrown exception
(for further verifications).
|
static <T,E extends Exception> |
catchException(T obj,
Class<E> clazz)
Use it to catch an exception of a specific type and to get access to the
thrown exception (for further verifications).
|
static <E extends Exception> |
caughtException()
Returns the exception caught during the last call on the proxied object
in the current thread.
|
static <T> T |
interfaces(T obj)
Returns a proxy that implements all interfaces of the underlying object.
|
private static <T,E extends Exception> |
processException(T obj,
Class<E> exceptionClazz,
boolean assertException)
Creates a proxy that processes exceptions thrown by the underlying
object.
|
static void |
resetCaughtException()
Sets the
caught exception to null. |
static <T> T |
verifyException(T obj)
Use it to verify that an exception is thrown and to get access to the
thrown exception (for further verifications).
|
static <T,E extends Exception> |
verifyException(T obj,
Class<E> clazz)
Use it to verify that an exception of specific type is thrown and to get
access to the thrown exception (for further verifications).
|
public CatchException()
public static <E extends Exception> E caughtException()
E
- This type parameter makes some type casts redundant.verifyException()
or
catchException()
. Returns
null the proxy has not caught an exception. Returns null if the
caught exception belongs to a class that is no longer
loaded
.public static <T> T verifyException(T obj)
The following example verifies that obj.doX() throws a Exception:
verifyException(obj).doX(); // catch and verify
assert "foobar".equals(caughtException().getMessage()); // further analysis
If doX()
does not throw a Exception
, then a
ExceptionNotThrownAssertionError
is thrown. Otherwise the thrown
exception can be retrieved via caughtException()
.
T
- The type of the given obj
.obj
- The instance that shall be proxied. Must not be
null
.public static <T,E extends Exception> T verifyException(T obj, Class<E> clazz)
The following example verifies that obj.doX() throws a MyException:
verifyException(obj, MyException.class).doX(); // catch and verify
assert "foobar".equals(caughtException().getMessage()); // further analysis
If doX()
does not throw a MyException
, then a
ExceptionNotThrownAssertionError
is thrown. Otherwise the thrown
exception can be retrieved via caughtException()
.
T
- The type of the given obj
.E
- The type of the exception that shall be caught.obj
- The instance that shall be proxied. Must not be
null
.clazz
- The type of the exception that shall be thrown by the
underlying object. Must not be null
.public static <T> T catchException(T obj)
In the following example you catch exceptions that are thrown by
obj.doX():
If catchException(obj).doX(); // catch
if (caughtException() != null) {
assert "foobar".equals(caughtException().getMessage()); // further analysis
}
doX()
throws a exception, then caughtException()
will return the caught exception. If doX()
does not throw a
exception, then caughtException()
will return null
.
T
- The type of the given obj
.obj
- The instance that shall be proxied. Must not be
null
.public static <T,E extends Exception> T catchException(T obj, Class<E> clazz)
In the following example you catch exceptions of type MyException that
are thrown by obj.doX():
If catchException(obj, MyException.class).doX(); // catch
if (caughtException() != null) {
assert "foobar".equals(caughtException().getMessage()); // further analysis
}
doX()
throws a MyException
, then
caughtException()
will return the caught exception. If
doX()
does not throw a MyException
, then
caughtException()
will return null
. If
doX()
throws an exception of another type, i.e. not a
subclass but another class, then this exception is not thrown and
caughtException()
will return null
.
T
- The type of the given obj
.E
- The type of the exception that shall be caught.obj
- The instance that shall be proxied. Must not be
null
.clazz
- The type of the exception that shall be caught. Must not be
null
.private static <T,E extends Exception> T processException(T obj, Class<E> exceptionClazz, boolean assertException)
Delegates to
SubclassProxyFactory.createProxy(Class, MethodInterceptor)
which
itself might delegate to
InterfaceOnlyProxyFactory.createProxy(Class, MethodInterceptor)
.
public static <T> T interfaces(T obj)
T
- must be an interface the object implementsobj
- the object that created proxy will delegate all calls topublic static void resetCaughtException()
caught exception
to null. This does
not affect exceptions saved at threads other than the current one.
Actually you probably never need to call this method because each method call on a proxied object in the current thread resets the caught exception. But if you want to improve test isolation or if you want to 'clean up' after testing (to avoid memory leaks), call the method before or after testing.
Copyright © 2014. All rights reserved.