package com.softwaremill.common.test.util; import org.testng.Assert; import static com.softwaremill.common.test.util.AssertException.ExceptionMatch.EXCEPTION_CLASS_MUST_EQUAL; /** * Allows expecting and intercepting exceptions in a nice way. * Use it to intercept exceptions in your tests, in a way that allows * sticking to the given/when/then flow, and validate exception throws on * <p/> * SoftwareBirr 02.2012 * * @author Konrad Malawski (konrad.malawski@java.pl) */ public class AssertException { public static abstract class ExceptionMatch { public static final ExceptionMatch.Strategy EXCEPTION_CLASS_MUST_EQUAL = new Strategy() { @Override public boolean matchesExpected(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage) { return got.getClass().equals(expectedClass); } public void failWithExpectedButGot(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage) { Assert.fail(String.format("Expected [%s] to be thrown but got [%s]", expectedClass.getSimpleName(), got.getClass().getSimpleName())); } }; /** * Please use EXCEPTION_CLASS_MUST_EQUAL instead */ @Deprecated public static final ExceptionMatch.Strategy EXCEPTION_MUST_EQUAL = EXCEPTION_CLASS_MUST_EQUAL; public static final ExceptionMatch.Strategy EXCEPTION_MAY_BE_SUBCLASS_OF = new Strategy() { @Override public boolean matchesExpected(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage) { return expectedClass.isAssignableFrom(got.getClass()); } public void failWithExpectedButGot(Class<? extends Throwable> expectedClass, Throwable got,String expectedMessage) { Assert.fail(String.format("Expected subclass of [%s] to be thrown but got [%s]", expectedClass.getSimpleName(), got.getClass().getSimpleName())); } }; public static final ExceptionMatch.Strategy EXCEPTION_CLASS_AND_MESSAGE_MUST_EQUAL = new Strategy() { @Override public boolean matchesExpected(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage) { return got.getClass().equals(expectedClass) && expectedMessage.equals(got.getMessage()); } public void failWithExpectedButGot(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage) { Assert.fail(String.format("Expected [%s] to be thrown with message [%s] but got [%s] with message [%s]", expectedClass.getSimpleName(), expectedMessage, got.getClass().getSimpleName(), got.getMessage())); } }; static interface Strategy { boolean matchesExpected(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage); void failWithExpectedButGot(Class<? extends Throwable> expectedClass, Throwable got, String expectedMessage); } } @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public static <T extends Throwable> void thrown(ExceptionMatch.Strategy matchStrategy, Class<T> expectedThrowableClass, Runnable block) { intercept(matchStrategy, expectedThrowableClass, block); } @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public static <T extends Throwable> void thrownWithMessage(ExceptionMatch.Strategy matchStrategy, Class<T> expectedThrowableClass, String expectedMessage, Runnable block) { intercept(matchStrategy, expectedThrowableClass, expectedMessage, block); } public static <T extends Throwable> void thrown(Class<T> expectedThrowableClass, Runnable block) { thrown(EXCEPTION_CLASS_MUST_EQUAL, expectedThrowableClass, block); } public static <T extends Throwable> T intercept(Class<T> expectedThrowableClass, Runnable block) { return intercept(EXCEPTION_CLASS_MUST_EQUAL, expectedThrowableClass, block); } public static <T extends Throwable> T intercept(ExceptionMatch.Strategy matchStrategy, Class<T> expectedThrowableClass, Runnable block) { return intercept(matchStrategy, expectedThrowableClass, null, block); } public static <T extends Throwable> T intercept(ExceptionMatch.Strategy matchStrategy, Class<T> expectedThrowableClass, String expectedMessage, Runnable block) { try { block.run(); failWithExpectedButGotNothing(expectedThrowableClass); // will throw return null; // make compiler happy } catch (Throwable thr) { Class<? extends Throwable> gotThrowableClass = thr.getClass(); boolean gotExpectedException = matchStrategy.matchesExpected(expectedThrowableClass, thr, expectedMessage); if (gotExpectedException) { return expectedThrowableClass.cast(thr); } else { matchStrategy.failWithExpectedButGot(expectedThrowableClass, thr, expectedMessage); return null; // make compiler happy } } } private static void failWithExpectedButGotNothing(Class<?> expected) { Assert.fail(String.format("Expected [%s] to be thrown but no exception was thrown.", expected.getSimpleName())); } }