1 package org.mockitoutil; 2 3 import org.assertj.core.api.AbstractThrowableAssert; 4 import org.assertj.core.api.Assertions; 5 import org.junit.rules.MethodRule; 6 import org.junit.runners.model.FrameworkMethod; 7 import org.junit.runners.model.Statement; 8 9 /** 10 * Junit rule for testing exception handling other JUnit rules, like Mockito JUnit rules. 11 * Makes it easy to assert on expected exceptions triggered by the rule under test. 12 */ 13 public class SafeJUnitRule implements MethodRule { 14 15 private final MethodRule testedRule; 16 private FailureAssert failureAssert = null; 17 private Runnable successAssert = new Runnable() { public void run() { } }; 18 19 /** 20 * Wraps rule under test with exception handling so that it is easy to assert on exceptions fired from the tested rule. 21 */ SafeJUnitRule(MethodRule testedRule)22 public SafeJUnitRule(MethodRule testedRule) { 23 this.testedRule = testedRule; 24 } 25 apply(final Statement base, final FrameworkMethod method, final Object target)26 public Statement apply(final Statement base, final FrameworkMethod method, final Object target) { 27 return new Statement() { 28 public void evaluate() throws Throwable { 29 try { 30 testedRule.apply(base, method, target).evaluate(); 31 successAssert.run(); 32 } catch (Throwable t) { 33 if (failureAssert == null) { 34 throw t; 35 } 36 failureAssert.doAssert(t); 37 return; 38 } 39 if (failureAssert != null) { 40 //looks like the user expects a throwable but it was not thrown! 41 throw new ExpectedThrowableNotReported("Expected the tested rule to throw an exception but it did not."); 42 } 43 } 44 }; 45 } 46 47 /** 48 * Expects that _after_ the test, the rule will fire specific exception with specific exception message 49 */ 50 public void expectFailure(final Class<? extends Throwable> expected, final String expectedMessage) { 51 this.expectFailure(new FailureAssert() { 52 public void doAssert(Throwable t) { 53 assertThrowable(t, expected).hasMessage(expectedMessage); 54 } 55 }); 56 } 57 58 /** 59 * Expects that _after_ the test, the rule will fire specific exception with specific exception message 60 */ 61 public void expectFailure(final Class<? extends Throwable> expected) { 62 this.expectFailure(new FailureAssert() { 63 public void doAssert(Throwable t) { 64 assertThrowable(t, expected); 65 } 66 }); 67 } 68 69 private static AbstractThrowableAssert assertThrowable(Throwable throwable, Class<? extends Throwable> expected) { 70 return Assertions.assertThat(throwable).isInstanceOf(expected); 71 } 72 73 /** 74 * Expects that _after_ the test, the rule will fire an exception 75 */ 76 public void expectFailure(FailureAssert failureAssert) { 77 this.failureAssert = failureAssert; 78 } 79 80 /** 81 * Expects that _after_ the test, given assert will run 82 */ 83 public void expectSuccess(Runnable successAssert) { 84 this.successAssert = successAssert; 85 } 86 87 /** 88 * Offers a way to assert the throwable triggered by the tested rule 89 */ 90 public interface FailureAssert { 91 void doAssert(Throwable t); 92 } 93 94 /** 95 * Thrown when user expects the tested rule to throw an exception but no exception was thrown 96 */ 97 class ExpectedThrowableNotReported extends Throwable { 98 public ExpectedThrowableNotReported(String message) { 99 super(message); 100 } 101 } 102 } 103