Skip to content

Commit

Permalink
Handle expected AssertionError and AssumptionViolatedException.
Browse files Browse the repository at this point in the history
Fixes junit-team#687. junit-team#121 is still fixed. (Pull request junit-team#323 was too rigid.)
  • Loading branch information
stefanbirkner committed Aug 17, 2013
1 parent 0e5be4e commit fc7bcdb
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 42 deletions.
128 changes: 99 additions & 29 deletions src/main/java/org/junit/rules/ExpectedException.java
Expand Up @@ -6,7 +6,6 @@
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;
Expand Down Expand Up @@ -63,35 +62,96 @@
* throw new NullPointerException("What happened?");
* }</pre>
*
* <h3>Verify AssertionErrors and AssumptionViolatedExceptions</h3>
* <h3>AssumptionViolatedExceptions</h3>
* <p>
* JUnit uses {@link AssumptionViolatedException}s for indicating
* that a test provides no useful information. (See {@link org.junit.Assume}
* for more information.) Therefore you have to call
* {@link #handleAssumptionViolatedExceptions()} if your test should fail
* when an unexpected {@code AssumptionViolatedException} is thrown.
*
* <p>
* 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()}.
* The assume methods of the {@code Assume} class are still working in
* conjuction with ExpectedException. Hence the following test is
* ignored by JUnit's default runner.
*
* <pre>
* &#064;Test
* public void throwsUnhandled () {
* thrown.expect(NullPointerException.class);
* assumeTrue(false); //throws AssumptionViolatedException
* }
* </pre>
*
* <p>A test that throws an expected {@code AssumptionViolatedException}
* is successful.
*
* <pre>
* // These tests all pass.
* public static class HasExpectedException {
* &#064;Rule
* public ExpectedException thrown= ExpectedException.none();
* &#064;Test
* public void throwsExpectedAssumptionViolatedException() {
* thrown.expect(AssumptionViolatedException.class);
* assumeTrue(false); //throws AssumptionViolatedException
* }
* </pre>
*
* &#064;Test
* public void throwExpectedAssertionError() {
* thrown.handleAssertionErrors();
* thrown.expect(AssertionError.class);
* throw new AssertionError();
* }
* <p>A test that throws an unexpected AssumptionViolatedException is not
* successful if {@link #handleAssumptionViolatedExceptions()} has been
* called. Hence the following test fails.
*
* <pre>
* &#064;Test
* public void throwExpectAssumptionViolatedException() {
* public void throwsExpectedAssumptionViolatedException() {
* thrown.handleAssumptionViolatedExceptions();
* thrown.expect(AssumptionViolatedException.class);
* throw new AssumptionViolatedException(&quot;&quot;);
* }
* }
* thrown.expect(NullPointerException.class);
* assumeTrue(false); //throws AssumptionViolatedException
* }
* </pre>
*
* <h3>AssertionErrors</h3>
*
* <p>
* JUnit uses {@link AssertionError}s for indicating that a test is
* failing. Therefore you have to call
* {@link #handleAssertionErrors()} if your test should fail
* when an unexpected {@code AssertionError} is thrown.
*
* <p>
* The assert methods of the {@code Assert} class are still working in
* conjuction with ExpectedException. Hence the following test fails
* because of the {@code assertTrue} statement.
*
* <pre>
* &#064;Test
* public void throwsUnhandled () {
* thrown.expect(NullPointerException.class);
* assertTrue(false); //throws AssertionError
* }
* </pre>
*
* <p>A test that throws an expected {@literal AssertionError} is
* successful.
*
* <pre>
* &#064;Test
* public void throwsExpectedAssumptionViolatedException() {
* thrown.expect(AssertionError.class);
* assertTrue(false); //throws AssertionError
* }
* </pre>
*
* <p>A test that throws an unexpected {@code AssertionError} is not
* successful if {@link #handleAssertionErrors()} has been called. Hence
* the following test fails because an
* {@code AssertionError} is thrown instead of a
* {@code NullPointerException}.
*
* <pre>
* &#064;Test
* public void throwsExpectedAssumptionViolatedException() {
* thrown.handleAssertionErrors();
* thrown.expect(NullPointerException.class);
* assumeTrue(false); //throws AssumptionViolatedException
* }
* </pre>
*
* <h3>Missing Exceptions</h3>
Expand Down Expand Up @@ -123,8 +183,9 @@ private ExpectedException() {
}

/**
* {@code AssertionErrors} are only considered by the rule if you call
* this method.
* Fail if {@code AssertionErrors} are not in line with the rule.
* By default such exceptions are passing this rule in order to be
* handled by the runner.
* @return the rule itself
*/
public ExpectedException handleAssertionErrors() {
Expand All @@ -133,8 +194,9 @@ public ExpectedException handleAssertionErrors() {
}

/**
* {@code AssumptionViolatedExceptions} are only considered by the rule
* if you call this method.
* Fail if {@code AssumptionViolatedExceptions} are not in line with
* the rule. By default such exceptions are passing this rule in
* order to be handled by the runner.
* @return the rule itself
*/
public ExpectedException handleAssumptionViolatedExceptions() {
Expand Down Expand Up @@ -254,7 +316,7 @@ public void evaluate() throws Throwable {
handleException(e);
return;
}
if (fMatcherBuilder.expectsThrowable()) {
if (isAnyExceptionExpection()) {
failDueToMissingException();
}
}
Expand All @@ -264,19 +326,27 @@ private void optionallyHandleException(Throwable e, boolean handleException)
throws Throwable {
if (handleException) {
handleException(e);
} else {
} else if (!isExpectedException(e)) {
throw e;
}
}

private boolean isExpectedException(Throwable e) {
return isAnyExceptionExpection() && fMatcherBuilder.build().matches(e);
}

private void handleException(Throwable e) throws Throwable {
if (fMatcherBuilder.expectsThrowable()) {
if (isAnyExceptionExpection()) {
assertThat(e, fMatcherBuilder.build());
} else {
throw e;
}
}

private boolean isAnyExceptionExpection() {
return fMatcherBuilder.expectsThrowable();
}

private void failDueToMissingException() throws AssertionError {
fail(missingExceptionMessage());
}
Expand Down
Expand Up @@ -61,24 +61,27 @@ public static Collection<Object[]> testsWithEventMatcher() {
ExpectedMessageMatcherFails.class,
hasSingleFailureWithMessage(startsWith("\nExpected: exception with message \"Wrong start\""))},
{ExpectsMatcher.class, everyTestRunSuccessful()},
{ThrowExpectedAssumptionViolatedException.class,
{
ViolateAssumptionAndExpectException.class,
hasSingleAssumptionFailure()},
{
ThrowExpectedAssumptionViolatedException.class,
everyTestRunSuccessful()},
{ThrowAssumptionViolatedExceptionButExpectOtherType.class,
hasSingleFailure()},
{
ThrowAssumptionViolatedExceptionButExpectOtherType.class,
hasSingleFailureWithMessage(containsString("Stacktrace was: org.junit.internal.AssumptionViolatedException"))},
{ViolateAssumptionAndExpectException.class,
hasSingleAssumptionFailure()},
{ThrowExpectedAssertionError.class, everyTestRunSuccessful()},
{
FailingTestWithExpectedException.class,
hasSingleFailureWithMessage(ARBITRARY_MESSAGE)},
{
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,
hasSingleFailureWithMessage(ARBITRARY_MESSAGE)},
{
ExpectsMultipleMatchers.class,
hasSingleFailureWithMessage(startsWith("\nExpected: (an instance of java.lang.IllegalArgumentException and exception with message a string containing \"Ack!\")"))},
Expand Down Expand Up @@ -257,12 +260,12 @@ public void throwsMore() {
}
}

public static class FailAndDontHandleAssertinErrors {
public static class FailingTestWithExpectedException {
@Rule
public ExpectedException thrown = none();

@Test
public void violatedAssumption() {
public void failingTest() {
thrown.expect(IllegalArgumentException.class);
fail(ARBITRARY_MESSAGE);
}
Expand All @@ -286,7 +289,6 @@ public static class ThrowExpectedAssertionError {

@Test
public void wrongException() {
thrown.handleAssertionErrors();
thrown.expect(AssertionError.class);
throw new AssertionError("the expected assertion error");
}
Expand All @@ -298,7 +300,6 @@ public static class DontThrowAssertionErrorButExpectOne {

@Test
public void assertionErrorExpectedButNonIsThrown() {
thrown.handleAssertionErrors();
thrown.expect(AssertionError.class);
}
}
Expand Down Expand Up @@ -333,7 +334,6 @@ public static class ThrowExpectedAssumptionViolatedException {

@Test
public void throwExpectAssumptionViolatedException() {
thrown.handleAssumptionViolatedExceptions();
thrown.expect(AssumptionViolatedException.class);
throw new AssumptionViolatedException("");
}
Expand Down

0 comments on commit fc7bcdb

Please sign in to comment.