Skip to content

Commit

Permalink
Update MultipleFailureException.assertEmpty() to wrap assumption
Browse files Browse the repository at this point in the history
failures if there are multiple exceptions.

This makes failures during the handling of assumption failures easier
to understand.
  • Loading branch information
kcooney committed Dec 5, 2016
1 parent ac273c0 commit edcb822
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 5 deletions.
19 changes: 19 additions & 0 deletions src/main/java/org/junit/TestCouldNotBeSkippedException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.junit;

/**
* Indicates that a test that indicated that it should be skipped could not be skipped.
* This can be thrown if a test uses the methods in {@link Assume} to indicate that
* it should be skipped, but before processing of the test was completed, other failures
* occured.
*
* @see org.junit.Assume
* @since 4.13
*/
public class TestCouldNotBeSkippedException extends RuntimeException {
private static final long serialVersionUID = 1L;

/** Creates an instance using the given assumption failure. */
public TestCouldNotBeSkippedException(org.junit.internal.AssumptionViolatedException cause) {
super("Test could not be skipped due to other failures", cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import java.util.Collections;
import java.util.List;

import org.junit.TestCouldNotBeSkippedException;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.Throwables;

/**
Expand All @@ -28,7 +30,13 @@ public MultipleFailureException(List<Throwable> errors) {
throw new IllegalArgumentException(
"List of Throwables must not be empty");
}
this.fErrors = new ArrayList<Throwable>(errors);
this.fErrors = new ArrayList<Throwable>(errors.size());
for (Throwable error : errors) {
if (error instanceof AssumptionViolatedException) {
error = new TestCouldNotBeSkippedException((AssumptionViolatedException) error);
}
fErrors.add(error);
}
}

public List<Throwable> getFailures() {
Expand Down
61 changes: 58 additions & 3 deletions src/test/java/org/junit/rules/ExternalResourceRuleTest.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package org.junit.rules;

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.experimental.results.PrintableResult.testResult;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.TestCouldNotBeSkippedException;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.statements.Fail;
import org.junit.runner.Description;
import org.junit.runners.model.MultipleFailureException;
Expand Down Expand Up @@ -72,4 +82,49 @@ protected void after() {
));
}
}

@Test
public void shouldWrapAssumptionFailuresWhenClosingResourceFails() throws Throwable {
// given
final AtomicReference<Throwable> externalResourceException = new AtomicReference<Throwable>();
ExternalResource resourceRule = new ExternalResource() {
@Override
protected void after() {
RuntimeException runtimeException = new RuntimeException("simulating resource tear down failure");
externalResourceException.set(runtimeException);
throw runtimeException;
}
};
final AtomicReference<Throwable> assumptionViolatedException = new AtomicReference<Throwable>();
Statement skippedTest = new Statement() {
@Override
public void evaluate() throws Throwable {
AssumptionViolatedException assumptionFailure = new AssumptionViolatedException("skip it");
assumptionViolatedException.set(assumptionFailure);
throw assumptionFailure;
}
};
Description dummyDescription = Description.createTestDescription(
"dummy test class name", "dummy test name");

try {
resourceRule.apply(skippedTest, dummyDescription).evaluate();
fail("ExternalResource should throw");
} catch (MultipleFailureException e) {
assertThat(e.getFailures(), hasItems(
instanceOf(TestCouldNotBeSkippedException.class),
sameInstance(externalResourceException.get())
));
assertThat(e.getFailures(), hasItems(
hasCause(sameInstance(assumptionViolatedException.get())),
sameInstance(externalResourceException.get())
));
}
}

@SuppressWarnings("unchecked")
private Matcher<? super List<Throwable>> hasItems(
Matcher<? super Throwable> one, Matcher<? super Throwable> two) {
return CoreMatchers.hasItems(one, two);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

Expand All @@ -12,7 +13,10 @@
import java.util.Collections;
import java.util.List;

import org.hamcrest.CoreMatchers;
import org.junit.Test;
import org.junit.TestCouldNotBeSkippedException;
import org.junit.internal.AssumptionViolatedException;
import org.junit.runners.model.MultipleFailureException;


Expand Down Expand Up @@ -80,6 +84,29 @@ public void assertEmptyErrorListConstructorFailure() {
}
}

@Test
public void assertEmptyWrapsAssumptionFailuresForManyThrowables() throws Exception {
List<Throwable> errors = new ArrayList<Throwable>();
AssumptionViolatedException assumptionViolatedException = new AssumptionViolatedException("skip it");
errors.add(assumptionViolatedException);
errors.add(new RuntimeException("garlic"));

try {
MultipleFailureException.assertEmpty(errors);
fail();
} catch (MultipleFailureException expected) {
assertThat(expected.getFailures().size(), equalTo(2));
assertTrue(expected.getMessage().startsWith("There were 2 errors:\n"));
assertTrue(expected.getMessage().contains("TestCouldNotBeSkippedException(Test could not be skipped"));
assertTrue(expected.getMessage().contains("RuntimeException(garlic)"));
Throwable first = expected.getFailures().get(0);
assertThat(first, instanceOf(TestCouldNotBeSkippedException.class));
Throwable cause = ((TestCouldNotBeSkippedException) first).getCause();
assertThat(cause, instanceOf(AssumptionViolatedException.class));
assertThat((AssumptionViolatedException) cause, CoreMatchers.sameInstance(assumptionViolatedException));
}
}

private static class ExpectedException extends RuntimeException {
private static final long serialVersionUID = 1L;

Expand Down

0 comments on commit edcb822

Please sign in to comment.