diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java index e559bc544c6c..3ee05b818cbf 100644 --- a/src/main/java/org/junit/rules/ExpectedException.java +++ b/src/main/java/org/junit/rules/ExpectedException.java @@ -6,86 +6,102 @@ import static org.junit.Assert.fail; import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; - import org.hamcrest.Matcher; import org.hamcrest.StringDescription; import org.junit.internal.AssumptionViolatedException; import org.junit.runners.model.Statement; /** - * The ExpectedException rule allows in-test specification of expected exception - * types and messages: + * The {@code ExpectedException} rule allows you to verify that your code + * throws a specific exception. * - *
- * // These tests all pass. - * public static class HasExpectedException { - * @Rule - * public ExpectedException thrown= ExpectedException.none(); + *+ *Usage
* - * @Test - * public void throwsNothing() { - * // no exception expected, none thrown: passes. - * } + *public class SimpleExpectedExceptionTest { + * @Rule + * public ExpectedException thrown= ExpectedException.none(); * - * @Test - * public void throwsNullPointerException() { - * thrown.expect(NullPointerException.class); - * throw new NullPointerException(); + * @Test + * public void throwsNothing() { + * // no exception expected, none thrown: passes. * } * - * @Test - * public void throwsNullPointerExceptionWithMessage() { - * thrown.expect(NullPointerException.class); - * thrown.expectMessage("happened?"); - * thrown.expectMessage(startsWith("What")); - * throw new NullPointerException("What happened?"); + * @Test + * public void throwsExceptionWithSpecificType() { + * thrown.expect(NullPointerException.class); + * throw new NullPointerException(); * } + * }+ * + *+ * You have to add the {@code ExpectedException} rule to your test. + * This doesn't affect your existing tests (see {@code throwsNothing()}). + * After specifiying the type of the expected exception your test is + * successful when such an exception is thrown and it fails if a + * different or no exception is thrown. * - * @Test - * public void throwsIllegalArgumentExceptionWithMessageAndCause() { - * NullPointerException expectedCause = new NullPointerException(); - * thrown.expect(IllegalArgumentException.class); - * thrown.expectMessage("What"); - * thrown.expectCause(is(expectedCause)); - * throw new IllegalArgumentException("What happened?", cause); - * } - * } - *
+ * Instead of specifying the exception's type you can characterize the + * expected exception based on other criterias, too: * - * By default ExpectedException rule doesn't handle AssertionErrors and - * AssumptionViolatedExceptions, because such exceptions are used by JUnit. If - * you want to handle such exceptions you have to call @link - * {@link #handleAssertionErrors()} or @link - * {@link #handleAssumptionViolatedExceptions()}. + *
- * // These tests all pass. - * public static class HasExpectedException { - * @Rule - * public ExpectedException thrown= ExpectedException.none(); + *+ *+ * You can combine any of the presented expect-methods. The test is + * successful if all specifications are met. + *
@Test + * public void throwsException() { + * thrown.expect(NullPointerException.class); + * thrown.expectMessage("happened"); + * throw new NullPointerException("What happened?"); + * }* - * @Test - * public void throwExpectedAssertionError() { - * thrown.handleAssertionErrors(); - * thrown.expect(AssertionError.class); - * throw new AssertionError(); - * } + *AssumptionViolatedExceptions
+ *+ * JUnit uses {@link AssumptionViolatedException}s for indicating that a test + * provides no useful information. (See {@link org.junit.Assume} for more + * information.) You have to call {@code assume} methods before you set + * expectations of the {@code ExpectedException} rule. In this case the rule + * will not handle consume the exceptions and it can be handled by the + * framework. E.g. the following test is ignored by JUnit's default runner. * - * @Test - * public void throwExpectAssumptionViolatedException() { - * thrown.handleAssumptionViolatedExceptions(); - * thrown.expect(AssumptionViolatedException.class); - * throw new AssumptionViolatedException(""); - * } - * } - *
@Test + * public void ignoredBecauseOfFailedAssumption() { + * assumeTrue(false); // throws AssumptionViolatedException + * thrown.expect(NullPointerException.class); + * }+ * + *
+ * JUnit uses {@link AssertionError}s for indicating that a test is failing. You + * have to call {@code assert} methods before you set expectations of the + * {@code ExpectedException} rule, if they should be handled by the framework. + * E.g. the following test fails because of the {@code assertTrue} statement. + * + *
@Test + * public void throwsUnhandled() { + * assertTrue(false); // throws AssertionError + * thrown.expect(NullPointerException.class); + * }+ * + *
+ * By default missing exceptions are reported with an error message + * like "Expected test to throw foo.". You can configure a different + * message by means of {@link #reportMissingExceptionWithMessage(String)}. * * @since 4.7 */ public class ExpectedException implements TestRule { /** - * @return a Rule that expects no exception to be thrown (identical to - * behavior without this Rule) + * Returns a {@linkplain TestRule rule} that expects no exception to + * be thrown (identical to behavior without this rule). */ public static ExpectedException none() { return new ExpectedException(); @@ -93,30 +109,36 @@ public static ExpectedException none() { private final ExpectedExceptionMatcherBuilder fMatcherBuilder = new ExpectedExceptionMatcherBuilder(); - private boolean handleAssumptionViolatedExceptions = false; - - private boolean handleAssertionErrors = false; - private String missingExceptionMessage; private ExpectedException() { } + /** + * This method does nothing. Don't use it. + * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just + * like in JUnit <= 4.10. + */ + @Deprecated public ExpectedException handleAssertionErrors() { - handleAssertionErrors = true; return this; } + /** + * This method does nothing. Don't use it. + * @deprecated AssumptionViolatedExceptions are handled by default since + * JUnit 4.12. Just like in JUnit <= 4.10. + */ + @Deprecated public ExpectedException handleAssumptionViolatedExceptions() { - handleAssumptionViolatedExceptions = true; return this; } - + /** * Specifies the failure message for tests that are expected to throw * an exception but do not throw any. * @param message exception detail message - * @return self + * @return the rule itself */ public ExpectedException reportMissingExceptionWithMessage(String message) { missingExceptionMessage = message; @@ -129,40 +151,67 @@ public Statement apply(Statement base, } /** - * Adds {@code matcher} to the list of requirements for any thrown - * exception. + * Verify that your code throws an exception that is matched by + * a Hamcrest matcher. + *
@Test + * public void throwsExceptionThatCompliesWithMatcher() { + * NullPointerException e = new NullPointerException(); + * thrown.expect(is(e)); + * throw e; + * }*/ public void expect(Matcher> matcher) { fMatcherBuilder.add(matcher); } /** - * Adds to the list of requirements for any thrown exception that it should - * be an instance of {@code type} + * Verify that your code throws an exception that is an + * instance of specific {@code type}. + *
@Test + * public void throwsExceptionWithSpecificType() { + * thrown.expect(NullPointerException.class); + * throw new NullPointerException(); + * } */ public void expect(Class extends Throwable> type) { expect(instanceOf(type)); } /** - * Adds to the list of requirements for any thrown exception that it should - * contain string {@code substring} + * Verify that your code throws an exception whose message contains + * a specific text. + *@Test + * public void throwsExceptionWhoseMessageContainsSpecificText() { + * thrown.expectMessage("happened"); + * throw new NullPointerException("What happened?"); + * }*/ public void expectMessage(String substring) { expectMessage(containsString(substring)); } /** - * Adds {@code matcher} to the list of requirements for the message returned - * from any thrown exception. + * Verify that your code throws an exception whose message is matched + * by a Hamcrest matcher. + *@Test + * public void throwsExceptionWhoseMessageCompliesWithMatcher() { + * thrown.expectMessage(startsWith("What")); + * throw new NullPointerException("What happened?"); + * }*/ public void expectMessage(Matchermatcher) { expect(hasMessage(matcher)); } /** - * Adds {@code matcher} to the list of requirements for the cause of - * any thrown exception. + * Verify that your code throws an exception whose cause is matched by + * a Hamcrest matcher. + * @Test + * public void throwsExceptionWhoseCauseCompliesWithMatcher() { + * NullPointerException expectedCause = new NullPointerException(); + * thrown.expectCause(is(expectedCause)); + * throw new IllegalArgumentException("What happened?", cause); + * }*/ public void expectCause(Matcher extends Throwable> expectedCause) { expect(hasCause(expectedCause)); @@ -179,39 +228,28 @@ public ExpectedExceptionStatement(Statement base) { public void evaluate() throws Throwable { try { fNext.evaluate(); - } catch (AssumptionViolatedException e) { - optionallyHandleException(e, handleAssumptionViolatedExceptions); - return; - } catch (AssertionError e) { - optionallyHandleException(e, handleAssertionErrors); - return; } catch (Throwable e) { handleException(e); return; } - if (fMatcherBuilder.expectsThrowable()) { + if (isAnyExceptionExpected()) { failDueToMissingException(); } } } - private void optionallyHandleException(Throwable e, boolean handleException) - throws Throwable { - if (handleException) { - handleException(e); - } else { - throw e; - } - } - private void handleException(Throwable e) throws Throwable { - if (fMatcherBuilder.expectsThrowable()) { + if (isAnyExceptionExpected()) { assertThat(e, fMatcherBuilder.build()); } else { throw e; } } + private boolean isAnyExceptionExpected() { + return fMatcherBuilder.expectsThrowable(); + } + private void failDueToMissingException() throws AssertionError { fail(missingExceptionMessage()); } diff --git a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java b/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java index 24eecfee20be..8a39d3b41ef6 100644 --- a/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java +++ b/src/test/java/org/junit/tests/experimental/rules/ExpectedExceptionTest.java @@ -22,7 +22,6 @@ import org.hamcrest.Matcher; import org.junit.Rule; import org.junit.Test; -import org.junit.internal.AssumptionViolatedException; import org.junit.rules.ExpectedException; import org.junit.runner.JUnitCore; import org.junit.runner.RunWith; @@ -61,23 +60,10 @@ public static Collection