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