My solution using Java 8 lambdas:
public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable { try { action.run(); Assert.fail("Did not throw expected " + expected.getSimpleName()); return null; // never actually } catch (Throwable actual) { if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)' System.err.println("Threw " + actual.getClass().getSimpleName() + ", which is not a subtype of expected " + expected.getSimpleName()); throw actual; // throw the unexpected Throwable for maximum transparency } else { return (T) actual; // return the expected Throwable for further examination } } }
You have to define a FunctionalInterface, because Runnable doesn't declare the required throws.
@FunctionalInterface public interface ThrowingRunnable { void run() throws Throwable; }
The method can be used as follows:
class CustomException extends Exception { public final String message; public CustomException(final String message) { this.message = message;} } CustomException e = assertThrows(CustomException.class, () -> { throw new CustomException("Lorem Ipsum"); }); assertEquals("Lorem Ipsum", e.message);
org.mockito.Mockito.verifywith various parameters to make sure that certain things happened (such that a logger service was called with the correct parameters) before the exception was thrown.