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);
+ * }
+ * + *

AssertionErrors

+ * + *

+ * 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);
+ * }
+ * + *

Missing Exceptions

+ *

+ * 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 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(Matcher matcher) { 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 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 testsWithEventMatcher() { ExpectedMessageMatcherFails.class, hasSingleFailureWithMessage(startsWith("\nExpected: exception with message \"Wrong start\""))}, {ExpectsMatcher.class, everyTestRunSuccessful()}, - {ThrowExpectedAssumptionViolatedException.class, - everyTestRunSuccessful()}, - {ThrowAssumptionViolatedExceptionButExpectOtherType.class, - hasSingleFailure()}, - { - ThrowAssumptionViolatedExceptionButExpectOtherType.class, - hasSingleFailureWithMessage(containsString("Stacktrace was: org.junit.internal.AssumptionViolatedException"))}, - {ViolateAssumptionAndExpectException.class, + {ExpectAssertionErrorWhichIsNotThrown.class, hasSingleFailure()}, + {FailedAssumptionAndExpectException.class, hasSingleAssumptionFailure()}, - {ThrowExpectedAssertionError.class, everyTestRunSuccessful()}, - { - DontThrowAssertionErrorButExpectOne.class, - hasSingleFailureWithMessage("Expected test to throw an instance of java.lang.AssertionError")}, - { - ThrowUnexpectedAssertionError.class, - hasSingleFailureWithMessage(startsWith("\nExpected: an instance of java.lang.NullPointerException"))}, - {FailAndDontHandleAssertinErrors.class, + {FailBeforeExpectingException.class, hasSingleFailureWithMessage(ARBITRARY_MESSAGE)}, { ExpectsMultipleMatchers.class, @@ -257,85 +243,36 @@ public void throwsMore() { } } - public static class FailAndDontHandleAssertinErrors { - @Rule - public ExpectedException thrown = none(); - - @Test - public void violatedAssumption() { - thrown.expect(IllegalArgumentException.class); - fail(ARBITRARY_MESSAGE); - } - } - - public static class ThrowUnexpectedAssertionError { - @Rule - public ExpectedException thrown = none(); - - @Test - public void wrongException() { - thrown.handleAssertionErrors(); - thrown.expect(NullPointerException.class); - throw new AssertionError("the unexpected assertion error"); - } - } - - public static class ThrowExpectedAssertionError { + //https://github.com/junit-team/junit/pull/583 + public static class ExpectAssertionErrorWhichIsNotThrown { @Rule public ExpectedException thrown = none(); @Test - public void wrongException() { - thrown.handleAssertionErrors(); + public void fails() { thrown.expect(AssertionError.class); - throw new AssertionError("the expected assertion error"); } } - public static class DontThrowAssertionErrorButExpectOne { + public static class FailBeforeExpectingException { @Rule public ExpectedException thrown = none(); @Test - public void assertionErrorExpectedButNonIsThrown() { - thrown.handleAssertionErrors(); - thrown.expect(AssertionError.class); + public void fails() { + fail(ARBITRARY_MESSAGE); + thrown.expect(IllegalArgumentException.class); } } - public static class ViolateAssumptionAndExpectException { + public static class FailedAssumptionAndExpectException { @Rule public ExpectedException thrown = none(); @Test - public void violatedAssumption() { - // expect an exception, which is not an AssumptionViolatedException - thrown.expect(NullPointerException.class); + public void failedAssumption() { assumeTrue(false); - } - } - - public static class ThrowAssumptionViolatedExceptionButExpectOtherType { - @Rule - public ExpectedException thrown = none(); - - @Test - public void wrongException() { - thrown.handleAssumptionViolatedExceptions(); thrown.expect(NullPointerException.class); - throw new AssumptionViolatedException(""); - } - } - - public static class ThrowExpectedAssumptionViolatedException { - @Rule - public ExpectedException thrown = none(); - - @Test - public void throwExpectAssumptionViolatedException() { - thrown.handleAssumptionViolatedExceptions(); - thrown.expect(AssumptionViolatedException.class); - throw new AssumptionViolatedException(""); } }