I have written a few JUnit tests with @Test
annotation. If my test method throws a checked exception and if I want to assert the message along with the exceptio
I like user64141's answer but found that it could be more generalized. Here's my take:
public abstract class ExpectedThrowableAsserter implements Runnable {
private final Class<? extends Throwable> throwableClass;
private final String expectedExceptionMessage;
protected ExpectedThrowableAsserter(Class<? extends Throwable> throwableClass, String expectedExceptionMessage) {
this.throwableClass = throwableClass;
this.expectedExceptionMessage = expectedExceptionMessage;
}
public final void run() {
try {
expectException();
} catch (Throwable e) {
assertTrue(String.format("Caught unexpected %s", e.getClass().getSimpleName()), throwableClass.isInstance(e));
assertEquals(String.format("%s caught, but unexpected message", throwableClass.getSimpleName()), expectedExceptionMessage, e.getMessage());
return;
}
fail(String.format("Expected %s, but no exception was thrown.", throwableClass.getSimpleName()));
}
protected abstract void expectException();
}
Note that leaving the "fail" statement within the try block causes the related assertion exception to be caught; using return within the catch statement prevents this.
Actually, the best usage is with try/catch. Why? Because you can control the place where you expect the exception.
Consider this example:
@Test (expected = RuntimeException.class)
public void someTest() {
// test preparation
// actual test
}
What if one day the code is modified and test preparation will throw a RuntimeException? In that case actual test is not even tested and even if it doesn't throw any exception the test will pass.
That is why it is much better to use try/catch than to rely on the annotation.
Import the catch-exception library, and use that. It's much cleaner than the ExpectedException
rule or a try-catch
.
Example form their docs:
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
catchException(myList).get(1);
// then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
assertThat(caughtException(),
allOf(
instanceOf(IndexOutOfBoundsException.class),
hasMessage("Index: 1, Size: 0"),
hasNoCause()
)
);
I like the @Rule answer. However, if for some reason you don't want to use rules. There is a third option.
@Test (expected = RuntimeException.class)
public void myTestMethod()
{
try
{
//Run exception throwing operation here
}
catch(RuntimeException re)
{
String message = "Employee ID is null";
assertEquals(message, re.getMessage());
throw re;
}
fail("Employee Id Null exception did not throw!");
}
If using @Rule, the exception set is applied to all the test methods in the Test class.
Do you have to use @Test(expected=SomeException.class)
? When we have to assert the actual message of the exception, this is what we do.
@Test
public void myTestMethod()
{
try
{
final Integer employeeId = null;
new Employee(employeeId);
fail("Should have thrown SomeException but did not!");
}
catch( final SomeException e )
{
final String msg = "Employee ID is null";
assertEquals(msg, e.getMessage());
}
}