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 = 22 new Runnable() { 23 public void run() {} 24 }; 25 26 /** 27 * Wraps rule under test with exception handling so that it is easy to assert on exceptions fired from the tested rule. 28 */ SafeJUnitRule(MethodRule testedRule)29 public SafeJUnitRule(MethodRule testedRule) { 30 this.testedRule = testedRule; 31 } 32 apply( final Statement base, final FrameworkMethod method, final Object target)33 public Statement apply( 34 final Statement base, final FrameworkMethod method, final Object target) { 35 return new Statement() { 36 public void evaluate() throws Throwable { 37 try { 38 testedRule.apply(base, method, target).evaluate(); 39 successAssert.run(); 40 } catch (Throwable t) { 41 if (failureAssert == null) { 42 throw t; 43 } 44 failureAssert.doAssert(t); 45 return; 46 } 47 if (failureAssert != null) { 48 // looks like the user expects a throwable but it was not thrown! 49 throw new ExpectedThrowableNotReported( 50 "Expected the tested rule to throw an exception but it did not."); 51 } 52 } 53 }; 54 } 55 56 /** 57 * Expects that _after_ the test, the rule will fire specific exception with specific exception message 58 */ 59 public void expectFailure( 60 final Class<? extends Throwable> expected, final String expectedMessage) { 61 this.expectFailure( 62 new FailureAssert() { 63 public void doAssert(Throwable t) { 64 assertThrowable(t, expected).hasMessage(expectedMessage); 65 } 66 }); 67 } 68 69 /** 70 * Expects that _after_ the test, the rule will fire specific exception with specific exception message 71 */ 72 public void expectFailure(final Class<? extends Throwable> expected) { 73 this.expectFailure( 74 new FailureAssert() { 75 public void doAssert(Throwable t) { 76 assertThrowable(t, expected); 77 } 78 }); 79 } 80 81 private static AbstractThrowableAssert assertThrowable( 82 Throwable throwable, Class<? extends Throwable> expected) { 83 return Assertions.assertThat(throwable).isInstanceOf(expected); 84 } 85 86 /** 87 * Expects that _after_ the test, the rule will fire an exception 88 */ 89 public void expectFailure(FailureAssert failureAssert) { 90 this.failureAssert = failureAssert; 91 } 92 93 /** 94 * Expects that _after_ the test, given assert will run 95 */ 96 public void expectSuccess(Runnable successAssert) { 97 this.successAssert = successAssert; 98 } 99 100 /** 101 * Offers a way to assert the throwable triggered by the tested rule 102 */ 103 public interface FailureAssert { 104 void doAssert(Throwable t); 105 } 106 107 /** 108 * Thrown when user expects the tested rule to throw an exception but no exception was thrown 109 */ 110 class ExpectedThrowableNotReported extends Throwable { 111 public ExpectedThrowableNotReported(String message) { 112 super(message); 113 } 114 } 115 } 116