Skip to content

Commit

Permalink
Fixes gh-121 (ExpectedException handles JUnit exceptions)
Browse files Browse the repository at this point in the history
ExpectedException rule no longer handles AssertionErrors and
AssumptionViolatedExceptions by default. This means that the
rule doesn't intercept if your test fails because of an violated
assertion or assumption.

If you want to test assertions or assumptions you have to tell
the rule to handle such exceptions via handleAssertionErrors()
or handleAssumptionViolatedExceptions().
  • Loading branch information
stefanbirkner committed Sep 21, 2011
1 parent 2d13004 commit 128553f
Show file tree
Hide file tree
Showing 6 changed files with 622 additions and 254 deletions.
101 changes: 81 additions & 20 deletions src/main/java/org/junit/rules/ExpectedException.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package org.junit.rules;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.both;
import static org.junit.matchers.JUnitMatchers.containsString;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.junit.Assert;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.matchers.TypeSafeMatcher;
import org.junit.runners.model.Statement;

/**
* The ExpectedException Rule allows in-test specification of expected exception
* The ExpectedException rule allows in-test specification of expected exception
* types and messages:
*
* <pre>
Expand All @@ -22,7 +23,7 @@
*
* &#064;Test
* public void throwsNothing() {
* // no exception expected, none thrown: passes.
* // no exception expected, none thrown: passes.
* }
*
* &#064;Test
Expand All @@ -40,31 +41,72 @@
* }
* }
* </pre>
*
* 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()}.
*
* <pre>
* // These tests all pass.
* public static class HasExpectedException {
* &#064;Rule
* public ExpectedException thrown= ExpectedException.none();
*
* &#064;Test
* public void throwExpectedAssertionError() {
* thrown.handleAssertionErrors();
* thrown.expect(AssertionError.class);
* throw new AssertionError();
* }
*
* &#064;Test
* public void throwExpectAssumptionViolatedException() {
* thrown.handleAssumptionViolatedExceptions();
* thrown.expect(AssumptionViolatedException.class);
* throw new AssumptionViolatedException(&quot;&quot;);
* }
* }
* </pre>
*/
public class ExpectedException implements TestRule {
/**
* @return a Rule that expects no exception to be thrown
* (identical to behavior without this Rule)
* @return a Rule that expects no exception to be thrown (identical to
* behavior without this Rule)
*/
public static ExpectedException none() {
return new ExpectedException();
}

private Matcher<Object> fMatcher= null;

private boolean handleAssumptionViolatedExceptions= false;

private boolean handleAssertionErrors= false;

private ExpectedException() {

}


public void handleAssertionErrors() {
handleAssertionErrors= true;
}

public void handleAssumptionViolatedExceptions() {
handleAssumptionViolatedExceptions= true;
}

public Statement apply(Statement base,
org.junit.runner.Description description) {
return new ExpectedExceptionStatement(base);
}

/**
* Adds {@code matcher} to the list of requirements for any thrown exception.
* Adds {@code matcher} to the list of requirements for any thrown
* exception.
*/
// Should be able to remove this suppression in some brave new hamcrest world.
// Should be able to remove this suppression in some brave new hamcrest
// world.
@SuppressWarnings("unchecked")
public void expect(Matcher<?> matcher) {
if (fMatcher == null)
Expand All @@ -74,24 +116,24 @@ public void expect(Matcher<?> matcher) {
}

/**
* Adds to the list of requirements for any thrown exception that it
* should be an instance of {@code type}
* Adds to the list of requirements for any thrown exception that it should
* be an instance of {@code type}
*/
public void expect(Class<? extends Throwable> type) {
expect(instanceOf(type));
}

/**
* Adds to the list of requirements for any thrown exception that it
* should <em>contain</em> string {@code substring}
* Adds to the list of requirements for any thrown exception that it should
* <em>contain</em> string {@code substring}
*/
public void expectMessage(String substring) {
expectMessage(containsString(substring));
}

/**
* Adds {@code matcher} to the list of requirements for the message
* returned from any thrown exception.
* Adds {@code matcher} to the list of requirements for the message returned
* from any thrown exception.
*/
public void expectMessage(Matcher<String> matcher) {
expect(hasMessage(matcher));
Expand All @@ -108,10 +150,14 @@ 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) {
if (fMatcher == null)
throw e;
Assert.assertThat(e, fMatcher);
handleException(e);
return;
}
if (fMatcher != null)
Expand All @@ -120,17 +166,32 @@ public void evaluate() throws Throwable {
}
}

private void optionallyHandleException(Throwable e, boolean handleException)
throws Throwable {
if (handleException)
handleException(e);
else
throw e;

}

private void handleException(Throwable e) throws Throwable {
if (fMatcher == null)
throw e;
assertThat(e, fMatcher);
}

private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
return new TypeSafeMatcher<Throwable>() {
public void describeTo(Description description) {
description.appendText("exception with message ");
description.appendDescriptionOf(matcher);
}

@Override
public boolean matchesSafely(Throwable item) {
return matcher.matches(item.getMessage());
}
};
}
}
}
58 changes: 58 additions & 0 deletions src/main/java/org/junit/runner/notification/EventCollector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.junit.runner.notification;

import java.util.ArrayList;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.Result;

public class EventCollector extends RunListener {
private final List<Description> testRunsStarted= new ArrayList<Description>();

private final List<Result> testRunsFinished= new ArrayList<Result>();

private final List<Description> testsStarted= new ArrayList<Description>();

private final List<Description> testsFinished= new ArrayList<Description>();

private final List<Failure> failures= new ArrayList<Failure>();

private final List<Failure> violatedAssumptions= new ArrayList<Failure>();

private final List<Description> testsIgnored= new ArrayList<Description>();

@Override
public void testRunStarted(Description description) throws Exception {
testRunsStarted.add(description);
}

@Override
public void testRunFinished(Result result) throws Exception {
testRunsFinished.add(result);
}

@Override
public void testStarted(Description description) throws Exception {
testsStarted.add(description);
}

@Override
public void testFinished(Description description) throws Exception {
testsFinished.add(description);
}

@Override
public void testFailure(Failure failure) throws Exception {
failures.add(failure);
}

@Override
public void testAssumptionFailure(Failure failure) {
violatedAssumptions.add(failure);
}

@Override
public void testIgnored(Description description) throws Exception {
testsIgnored.add(description);
}
}
4 changes: 2 additions & 2 deletions src/test/java/org/junit/tests/AllTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.junit.tests.experimental.parallel.ParallelMethodTest;
import org.junit.tests.experimental.rules.BlockJUnit4ClassRunnerOverrideTest;
import org.junit.tests.experimental.rules.ClassRulesTest;
import org.junit.tests.experimental.rules.ExpectedExceptionRuleTest;
import org.junit.tests.experimental.rules.ExpectedExceptionTest;
import org.junit.tests.experimental.rules.ExternalResourceRuleTest;
import org.junit.tests.experimental.rules.MethodRulesTest;
import org.junit.tests.experimental.rules.NameRulesTest;
Expand Down Expand Up @@ -144,7 +144,7 @@
ParentRunnerTest.class,
NameRulesTest.class,
ClassRulesTest.class,
ExpectedExceptionRuleTest.class,
ExpectedExceptionTest.class,
TempFolderRuleTest.class,
ExternalResourceRuleTest.class,
VerifierRuleTest.class,
Expand Down
Loading

0 comments on commit 128553f

Please sign in to comment.