package org.mockitoutil;
import org.assertj.core.api.AbstractThrowableAssert;
import org.assertj.core.api.Assertions;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
/**
* Junit rule for testing exception handling other JUnit rules, like Mockito JUnit rules.
* Makes it easy to assert on expected exceptions triggered by the rule under test.
*/
public class SafeJUnitRule implements MethodRule {
private final MethodRule testedRule;
private FailureAssert failureAssert = null;
private Runnable successAssert = new Runnable() { public void run() { } };
/**
* Wraps rule under test with exception handling so that it is easy to assert on exceptions fired from the tested rule.
*/
public SafeJUnitRule(MethodRule testedRule) {
this.testedRule = testedRule;
}
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
public void evaluate() throws Throwable {
try {
testedRule.apply(base, method, target).evaluate();
successAssert.run();
} catch (Throwable t) {
if (failureAssert == null) {
throw t;
}
failureAssert.doAssert(t);
return;
}
if (failureAssert != null) {
//looks like the user expects a throwable but it was not thrown!
throw new ExpectedThrowableNotReported("Expected the tested rule to throw an exception but it did not.");
}
}
};
}
/**
* Expects that _after_ the test, the rule will fire specific exception with specific exception message
*/
public void expectFailure(final Class<? extends Throwable> expected, final String expectedMessage) {
this.expectFailure(new FailureAssert() {
public void doAssert(Throwable t) {
assertThrowable(t, expected).hasMessage(expectedMessage);
}
});
}
/**
* Expects that _after_ the test, the rule will fire specific exception with specific exception message
*/
public void expectFailure(final Class<? extends Throwable> expected) {
this.expectFailure(new FailureAssert() {
public void doAssert(Throwable t) {
assertThrowable(t, expected);
}
});
}
private static AbstractThrowableAssert assertThrowable(Throwable throwable, Class<? extends Throwable> expected) {
return Assertions.assertThat(throwable).isInstanceOf(expected);
}
/**
* Expects that _after_ the test, the rule will fire an exception
*/
public void expectFailure(FailureAssert failureAssert) {
this.failureAssert = failureAssert;
}
/**
* Expects that _after_ the test, given assert will run
*/
public void expectSuccess(Runnable successAssert) {
this.successAssert = successAssert;
}
/**
* Offers a way to assert the throwable triggered by the tested rule
*/
public interface FailureAssert {
void doAssert(Throwable t);
}
/**
* Thrown when user expects the tested rule to throw an exception but no exception was thrown
*/
class ExpectedThrowableNotReported extends Throwable {
public ExpectedThrowableNotReported(String message) {
super(message);
}
}
}