diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java index 961c5cef72b6..a3d7905e6d24 100644 --- a/src/main/java/org/junit/Assert.java +++ b/src/main/java/org/junit/Assert.java @@ -968,17 +968,19 @@ public static void assertThat(String reason, T actual, /** * Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when - * executed. If it does not throw an exception, an {@link AssertionError} is thrown. If it - * throws the wrong type of exception, an {@code AssertionError} is thrown describing the - * mismatch; the exception that was actually thrown can be obtained by calling {@link - * AssertionError#getCause}. + * executed. If it does, the exception object is returned. If it does not throw an exception, an + * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code + * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can + * be obtained by calling {@link AssertionError#getCause}. * * @param expectedThrowable the expected type of the exception * @param runnable a function that is expected to throw an exception when executed + * @return the exception thrown by {@code runnable} * @since 4.13 */ - public static void assertThrows(Class expectedThrowable, ThrowingRunnable runnable) { - expectThrows(expectedThrowable, runnable); + public static T assertThrows(Class expectedThrowable, + ThrowingRunnable runnable) { + return assertThrows(null, expectedThrowable, runnable); } /** @@ -988,12 +990,15 @@ public static void assertThrows(Class expectedThrowable, Th * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can * be obtained by calling {@link AssertionError#getCause}. * + * @param message the identifying message for the {@link AssertionError} (null + * okay) * @param expectedThrowable the expected type of the exception - * @param runnable a function that is expected to throw an exception when executed + * @param runnable a function that is expected to throw an exception when executed * @return the exception thrown by {@code runnable} * @since 4.13 */ - public static T expectThrows(Class expectedThrowable, ThrowingRunnable runnable) { + public static T assertThrows(String message, Class expectedThrowable, + ThrowingRunnable runnable) { try { runnable.run(); } catch (Throwable actualThrown) { @@ -1010,7 +1015,8 @@ public static T expectThrows(Class expectedThrowable, T expected += "@" + Integer.toHexString(System.identityHashCode(expectedThrowable)); actual += "@" + Integer.toHexString(System.identityHashCode(actualThrowable)); } - String mismatchMessage = format("unexpected exception type thrown;", expected, actual); + String mismatchMessage = buildPrefix(message) + + format("unexpected exception type thrown;", expected, actual); // The AssertionError(String, Throwable) ctor is only available on JDK7. AssertionError assertionError = new AssertionError(mismatchMessage); @@ -1018,8 +1024,13 @@ public static T expectThrows(Class expectedThrowable, T throw assertionError; } } - String message = String.format("expected %s to be thrown, but nothing was thrown", - formatClass(expectedThrowable)); - throw new AssertionError(message); + String notThrownMessage = buildPrefix(message) + String + .format("expected %s to be thrown, but nothing was thrown", + formatClass(expectedThrowable)); + throw new AssertionError(notThrownMessage); + } + + private static String buildPrefix(String message) { + return message != null && message.length() != 0 ? message + ": " : ""; } } diff --git a/src/main/java/org/junit/function/ThrowingRunnable.java b/src/main/java/org/junit/function/ThrowingRunnable.java index 6e05d85c6580..d0eb782ccd30 100644 --- a/src/main/java/org/junit/function/ThrowingRunnable.java +++ b/src/main/java/org/junit/function/ThrowingRunnable.java @@ -1,8 +1,10 @@ package org.junit.function; /** - * This interface facilitates the use of expectThrows from Java 8. It allows method references - * to void methods (that declare checked exceptions) to be passed directly into expectThrows + * This interface facilitates the use of + * {@link org.junit.Assert#assertThrows(Class, ThrowingRunnable)} from Java 8. It allows method + * references to void methods (that declare checked exceptions) to be passed directly into + * {@code assertThrows} * without wrapping. It is not meant to be implemented directly. * * @since 4.13 diff --git a/src/main/java/org/junit/rules/ExpectedException.java b/src/main/java/org/junit/rules/ExpectedException.java index 71f551a2889e..51e26162e2f3 100644 --- a/src/main/java/org/junit/rules/ExpectedException.java +++ b/src/main/java/org/junit/rules/ExpectedException.java @@ -18,10 +18,7 @@ * {@link org.junit.Assert#assertThrows(java.lang.Class, org.junit.function.ThrowingRunnable) * Assert.assertThrows} * is often a better choice since it allows you to express exactly where you - * expect the exception to be thrown. Use - * {@link org.junit.Assert#expectThrows(java.lang.Class, - * org.junit.function.ThrowingRunnable) expectThrows} - * if you need to assert something about the thrown exception. + * expect the exception to be thrown. * *

Usage

* diff --git a/src/test/java/org/junit/tests/assertion/AssertionTest.java b/src/test/java/org/junit/tests/assertion/AssertionTest.java index ed7ddd1d0980..d0c3bdfddc59 100644 --- a/src/test/java/org/junit/tests/assertion/AssertionTest.java +++ b/src/test/java/org/junit/tests/assertion/AssertionTest.java @@ -11,7 +11,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.expectThrows; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import java.io.IOException; @@ -848,14 +848,14 @@ public void assertNotEqualsIgnoresFloatDeltaOnNaN() { } @Test(expected = AssertionError.class) - public void expectThrowsRequiresAnExceptionToBeThrown() { - expectThrows(Throwable.class, nonThrowingRunnable()); + public void assertThrowsRequiresAnExceptionToBeThrown() { + assertThrows(Throwable.class, nonThrowingRunnable()); } @Test - public void expectThrowsIncludesAnInformativeDefaultMessage() { + public void assertThrowsIncludesAnInformativeDefaultMessage() { try { - expectThrows(Throwable.class, nonThrowingRunnable()); + assertThrows(Throwable.class, nonThrowingRunnable()); } catch (AssertionError ex) { assertEquals("expected java.lang.Throwable to be thrown, but nothing was thrown", ex.getMessage()); return; @@ -864,27 +864,40 @@ public void expectThrowsIncludesAnInformativeDefaultMessage() { } @Test - public void expectThrowsReturnsTheSameObjectThrown() { + public void assertThrowsIncludesTheSpecifiedMessage() { + try { + assertThrows("Foobar", Throwable.class, nonThrowingRunnable()); + } catch (AssertionError ex) { + assertEquals( + "Foobar: expected java.lang.Throwable to be thrown, but nothing was thrown", + ex.getMessage()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsReturnsTheSameObjectThrown() { NullPointerException npe = new NullPointerException(); - Throwable throwable = expectThrows(Throwable.class, throwingRunnable(npe)); + Throwable throwable = assertThrows(Throwable.class, throwingRunnable(npe)); assertSame(npe, throwable); } @Test(expected = AssertionError.class) - public void expectThrowsDetectsTypeMismatchesViaExplicitTypeHint() { + public void assertThrowsDetectsTypeMismatchesViaExplicitTypeHint() { NullPointerException npe = new NullPointerException(); - expectThrows(IOException.class, throwingRunnable(npe)); + assertThrows(IOException.class, throwingRunnable(npe)); } @Test - public void expectThrowsWrapsAndPropagatesUnexpectedExceptions() { + public void assertThrowsWrapsAndPropagatesUnexpectedExceptions() { NullPointerException npe = new NullPointerException("inner-message"); try { - expectThrows(IOException.class, throwingRunnable(npe)); + assertThrows(IOException.class, throwingRunnable(npe)); } catch (AssertionError ex) { assertSame(npe, ex.getCause()); assertEquals("inner-message", ex.getCause().getMessage()); @@ -894,11 +907,11 @@ public void expectThrowsWrapsAndPropagatesUnexpectedExceptions() { } @Test - public void expectThrowsSuppliesACoherentErrorMessageUponTypeMismatch() { + public void assertThrowsSuppliesACoherentErrorMessageUponTypeMismatch() { NullPointerException npe = new NullPointerException(); try { - expectThrows(IOException.class, throwingRunnable(npe)); + assertThrows(IOException.class, throwingRunnable(npe)); } catch (AssertionError error) { assertEquals("unexpected exception type thrown; expected: but was:", error.getMessage()); @@ -909,11 +922,26 @@ public void expectThrowsSuppliesACoherentErrorMessageUponTypeMismatch() { } @Test - public void expectThrowsUsesCanonicalNameUponTypeMismatch() { + public void assertThrowsSuppliesTheSpecifiedMessageUponTypeMismatch() { + NullPointerException npe = new NullPointerException(); + + try { + assertThrows("Foobar", IOException.class, throwingRunnable(npe)); + } catch (AssertionError error) { + assertEquals("Foobar: unexpected exception type thrown; expected: but was:", + error.getMessage()); + assertSame(npe, error.getCause()); + return; + } + throw new AssertionError(ASSERTION_ERROR_EXPECTED); + } + + @Test + public void assertThrowsUsesCanonicalNameUponTypeMismatch() { NullPointerException npe = new NullPointerException(); try { - expectThrows(NestedException.class, throwingRunnable(npe)); + assertThrows(NestedException.class, throwingRunnable(npe)); } catch (AssertionError error) { assertEquals( "unexpected exception type thrown; expected:" @@ -926,12 +954,12 @@ public void expectThrowsUsesCanonicalNameUponTypeMismatch() { } @Test - public void expectThrowsUsesNameUponTypeMismatchWithAnonymousClass() { + public void assertThrowsUsesNameUponTypeMismatchWithAnonymousClass() { NullPointerException npe = new NullPointerException() { }; try { - expectThrows(IOException.class, throwingRunnable(npe)); + assertThrows(IOException.class, throwingRunnable(npe)); } catch (AssertionError error) { assertEquals( "unexpected exception type thrown; expected:" @@ -944,9 +972,9 @@ public void expectThrowsUsesNameUponTypeMismatchWithAnonymousClass() { } @Test - public void expectThrowsUsesCanonicalNameWhenRequiredExceptionNotThrown() { + public void assertThrowsUsesCanonicalNameWhenRequiredExceptionNotThrown() { try { - expectThrows(NestedException.class, nonThrowingRunnable()); + assertThrows(NestedException.class, nonThrowingRunnable()); } catch (AssertionError error) { assertEquals( "expected org.junit.tests.assertion.AssertionTest.NestedException to be thrown,"