This JUnit extension allows you to test for exceptions as you would test for other conditions, often as:
assertThrows(emptyList).get(0);
This is an alpha release. The package names, API, and features may change in a future release.
Traditionally, there are two ways to verify that code throws exceptions as expected: using an
annotation, and using try-fail-catch.
However both are more complex than using assertTrue
or assertEquals
.
This project offers two additional, sometimes simpler ways to test for exceptions: using
assertThrows() and using
new AssertThrows().
If the test method itself is expected to throw an IndexOutOfBoundsException
,
use the following annotation
as described in JUnit FAQ:
@Test(expected=IndexOutOfBoundsException.class) public void testIndexOutOfBoundsException() { List<String> emptyList = new ArrayList<String>(); emptyList.get(0); }
If the test is more complex and doesn't end where the exception is expected, you could write:
List<String> emptyList = new ArrayList<String>(); try { emptyList.get(0); fail(); } catch (IndexOutOfBoundsException e) { // expected }
This will allow you to verify the exception message as well.
However, it is very easy to forget the fail()
.
In many cases, this project allows you to simplify such tests to:
List<String> emptyList = new ArrayList<String>(); assertThrows(emptyList).get(0);
Please note the somewhat unusual order of brackets. To verify the correct exception is thrown, use:
assertThrows(IndexOutOfBoundsException.class, emptyList).get(0);
To verify the exception message as well, use:
assertThrows(new IndexOutOfBoundsException( "Index: 0, Size: 0"), emptyList). get(0);
Please note you need to add the following static import statement:
import static org.junit.contrib.assertthrows.AssertThrows.assertThrows;
Internally, the assertThrows
creates a proxy for the emptyList
object,
which verifies all method calls to this object throw an exception.
Static methods and constructors can't be tested in this way.
Testing the finalize
method is not supported.
This solution works best with interfaces (as in this example the List
interface).
By default, assertThrows
will try to create a proxy
using the java.lang.reflect.Proxy
mechanism.
For classes that do not implement an interface, and to test methods that are not part of any interface,
a class proxy is required (a proxy that extends a class, and not just implements interfaces).
Because this is tricky, assertThrows
doesn't do that by default.
To explicitly use a class proxy, call AssertThrows.useClassProxy
.
As an example, if you declare emptyList
to be an instance
of the concrete class ArrayList
, you need to tell the tool to use a class proxy:
ArrayList<String> emptyList = new ArrayList<String>(); AssertThrows.useClassProxy(ArrayList.class); assertThrows(emptyList).get(0);
Once such a class proxy is created, it is used for all future assertThrows
calls
where the provided object is of this class.
Creating a proxy that extends a class is a bit challenging.
It is not possibly to create a proxy for a final class, because extending a final class is not allowed.
Also, final methods can not be overridden.
Creating a class proxy on a class proxy itself is not supported.
To create class proxies, the proxy factory uses the libraries
Cglib and
Objenesis if they are in the classpath.
If not, Java source code for the proxy class is generated,
and then compiled using javax.tools.JavaCompiler
(Java 6)
or com.sun.tools.javac.Main
(Java 5). This does have a few limitations:
private classes, non-static inner classes, and anonymous inner classes are not supported.
Also, classes without public constructors are not supported. Most of those limitations do not
apply when using Cglib and Objenesis however.
A final method can not be overridden, and therefore the tool can not verify
whether it threw an exception. However, such cases are detected
on the next usage (the next call to assertThrows
, and the
next time an AssertThrows
object is created),
or when the proxy is garbage collected.
So if you made a mistake and called a final method, or did not call method
on the proxy assertThrows
object, the tool will usually detect it.
As an example, the following code will throw an exception saying
that no method was called on the proxy:
List<String> list = new ArrayList<String>(); assertThrows(list); assertThrows(list).get(0);
You may also verify the usage explicitly by calling ExceptionVerifier.verifyLastProxyWasUsed()
,
for example in a tearDown
method or JUnit 4 Rule
.
The following syntax is supported:
new AssertThrows() { public void test() { Integer.parseInt("x"); }};
The constructor of this class calls test()
and verifies it throws an exception.
To test for a specific exception, use:
new AssertThrows(NumberFormatException.class) { public void test() { Integer.parseInt("x"); }};
You may also test for a specific exception message using:
new AssertThrows(new NumberFormatException("For input string: \"x\"")) { public void test() { Integer.parseInt("x"); }};
Please note you need to add the following import statement:
import org.junit.contrib.assertthrows.AssertThrows;
If you need to verify the exception in more detail (for example, match the message against a pattern, or verify the cause), you can get the last exception or error as follows:
Throwable t = AssertThrows.getLastThrown();
This will get the last exception or error that was thrown by a test
in the current thread, no matter if the proxy mechanism (assertThrows
)
or the anonymous class mechanism (new AssertThrows
) was used.
If the last executed test did not throw an exception, it will return null.
Please note even thought this is a static method, it is multi-threading save because
it uses a ThreadLocal
variable internally.
To use this tool, download add the .jar
file to your project.
A minimal test case is:
import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.contrib.assertthrows.AssertThrows; import static org.junit.contrib.assertthrows.AssertThrows.*; public class HelloAssertThrows { @Test public void test() { final List<String> emptyList = new ArrayList<String>(); assertThrows(emptyList).get(0); new AssertThrows() { public void test() { emptyList.get(0); }}; } }
The jar file is not yet in a Maven central repository, but you can build and deploy it locally if you wish.
To do that, first download the .zip
or .tar.gz
file, and build it using:
cd assertthrows mvn clean install
Then use the following dependency:
<dependency> <groupId>org.junit.contrib</groupId> <artifactId>junit-assertthrows</artifactId> <version>0.1-SNAPSHOT</version> <scope>test</scope> </dependency>
For bugs and feature requests, please use the issue tracker.
To clone the project with Git, run:
git clone git://github.com/dsaff/junit.contrib
This project does not required additional libraries. However, if you want to test using class proxies, it is suggested to add the libraries Cglib and Objenesis to the classpath while running the tests. Please note those are optional dependencies only; within the described limitations, this tool works without them. To add the dependencies to a Maven project, use:
<dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.objenesis</groupId> <artifactId>objenesis</artifactId> <version>1.2</version> <scope>test</scope> </dependency>
This project uses the Apache License Version 2.0.
There are classpath problems when using Maven 2.x. together with the the compiling proxy factory. If the compiling proxy factory is required, you will need to use Maven 3.x.