package org.junit.rules;
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.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;
import org.junit.runners.model.Statement;
public class ExternalResourceRuleTest {
private static String callSequence;
public static class UsesExternalResource {
@Rule
public ExternalResource resource = new ExternalResource() {
@Override
protected void before() throws Throwable {
callSequence += "before ";
}
;
@Override
protected void after() {
callSequence += "after ";
}
;
};
@Test
public void testFoo() {
callSequence += "test ";
}
}
@Test
public void externalResourceGeneratesCorrectSequence() {
callSequence = "";
assertThat(testResult(UsesExternalResource.class), isSuccessful());
assertEquals("before test after ", callSequence);
}
@Test
public void shouldThrowMultipleFailureExceptionWhenTestFailsAndClosingResourceFails() throws Throwable {
// given
ExternalResource resourceRule = new ExternalResource() {
@Override
protected void after() {
throw new RuntimeException("simulating resource tear down failure");
}
};
Statement failingTest = new Fail(new RuntimeException("simulated test failure"));
Description dummyDescription = Description.createTestDescription(
"dummy test class name", "dummy test name");
try {
resourceRule.apply(failingTest, dummyDescription).evaluate();
fail("ExternalResource should throw");
} catch (MultipleFailureException e) {
assertThat(e.getMessage(), allOf(
containsString("simulated test failure"),
containsString("simulating resource tear down failure")
));
}
}
@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);
}
}