001package org.junit.rules; 002 003import static java.lang.String.format; 004import static org.hamcrest.CoreMatchers.containsString; 005import static org.hamcrest.CoreMatchers.instanceOf; 006import static org.junit.Assert.assertThat; 007import static org.junit.Assert.fail; 008import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause; 009import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; 010import org.hamcrest.Matcher; 011import org.hamcrest.StringDescription; 012import org.junit.AssumptionViolatedException; 013import org.junit.runners.model.Statement; 014 015/** 016 * The {@code ExpectedException} rule allows you to verify that your code 017 * throws a specific exception. 018 * 019 * <h3>Usage</h3> 020 * 021 * <pre> public class SimpleExpectedExceptionTest { 022 * @Rule 023 * public ExpectedException thrown = ExpectedException.none(); 024 * 025 * @Test 026 * public void throwsNothing() { 027 * // no exception expected, none thrown: passes. 028 * } 029 * 030 * @Test 031 * public void throwsExceptionWithSpecificType() { 032 * thrown.expect(NullPointerException.class); 033 * throw new NullPointerException(); 034 * } 035 * }</pre> 036 * 037 * <p>You have to add the {@code ExpectedException} rule to your test. 038 * This doesn't affect your existing tests (see {@code throwsNothing()}). 039 * After specifying the type of the expected exception your test is 040 * successful when such an exception is thrown and it fails if a 041 * different or no exception is thrown. 042 * 043 * <p>This rule does not perform any special magic to make execution continue 044 * as if the exception had not been thrown. So it is nearly always a mistake 045 * for a test method to have statements after the one that is expected to 046 * throw the exception. 047 * 048 * <p>Instead of specifying the exception's type you can characterize the 049 * expected exception based on other criteria, too: 050 * 051 * <ul> 052 * <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li> 053 * <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li> 054 * <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li> 055 * <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li> 056 * </ul> 057 * 058 * <p>You can combine any of the presented expect-methods. The test is 059 * successful if all specifications are met. 060 * <pre> @Test 061 * public void throwsException() { 062 * thrown.expect(NullPointerException.class); 063 * thrown.expectMessage("happened"); 064 * throw new NullPointerException("What happened?"); 065 * }</pre> 066 * 067 * <p>It is recommended to set the {@link org.junit.Rule#order() order} of the 068 * {@code ExpectedException} to {@code Integer.MAX_VALUE} if it is used together 069 * with another rule that handles exceptions, e.g. {@link ErrorCollector}. 070 * Otherwise failing tests may be successful. 071 * <pre> @Rule(order = Integer.MAX_VALUE) 072 * public ExpectedException thrown = ExpectedException.none();</pre> 073 * 074 * <h3>AssumptionViolatedExceptions</h3> 075 * <p>JUnit uses {@link AssumptionViolatedException}s for indicating that a test 076 * provides no useful information. (See {@link org.junit.Assume} for more 077 * information.) You have to call {@code assume} methods before you set 078 * expectations of the {@code ExpectedException} rule. In this case the rule 079 * will not handle consume the exceptions and it can be handled by the 080 * framework. E.g. the following test is ignored by JUnit's default runner. 081 * 082 * <pre> @Test 083 * public void ignoredBecauseOfFailedAssumption() { 084 * assumeTrue(false); // throws AssumptionViolatedException 085 * thrown.expect(NullPointerException.class); 086 * }</pre> 087 * 088 * <h3>AssertionErrors</h3> 089 * 090 * <p>JUnit uses {@link AssertionError}s for indicating that a test is failing. You 091 * have to call {@code assert} methods before you set expectations of the 092 * {@code ExpectedException} rule, if they should be handled by the framework. 093 * E.g. the following test fails because of the {@code assertTrue} statement. 094 * 095 * <pre> @Test 096 * public void throwsUnhandled() { 097 * assertTrue(false); // throws AssertionError 098 * thrown.expect(NullPointerException.class); 099 * }</pre> 100 * 101 * <h3>Missing Exceptions</h3> 102 * <p>By default missing exceptions are reported with an error message 103 * like "Expected test to throw an instance of foo". You can configure a different 104 * message by means of {@link #reportMissingExceptionWithMessage(String)}. You 105 * can use a {@code %s} placeholder for the description of the expected 106 * exception. E.g. "Test doesn't throw %s." will fail with the error message 107 * "Test doesn't throw an instance of foo.". 108 * 109 * @since 4.7 110 */ 111public class ExpectedException implements TestRule { 112 /** 113 * Returns a {@linkplain TestRule rule} that expects no exception to 114 * be thrown (identical to behavior without this rule). 115 * 116 * @deprecated Since 4.13 117 * {@link org.junit.Assert#assertThrows(Class, org.junit.function.ThrowingRunnable) 118 * Assert.assertThrows} can be used to verify that your code throws a specific 119 * exception. 120 */ 121 @Deprecated 122 public static ExpectedException none() { 123 return new ExpectedException(); 124 } 125 126 private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder(); 127 128 private String missingExceptionMessage= "Expected test to throw %s"; 129 130 private ExpectedException() { 131 } 132 133 /** 134 * This method does nothing. Don't use it. 135 * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just 136 * like in JUnit <= 4.10. 137 */ 138 @Deprecated 139 public ExpectedException handleAssertionErrors() { 140 return this; 141 } 142 143 /** 144 * This method does nothing. Don't use it. 145 * @deprecated AssumptionViolatedExceptions are handled by default since 146 * JUnit 4.12. Just like in JUnit <= 4.10. 147 */ 148 @Deprecated 149 public ExpectedException handleAssumptionViolatedExceptions() { 150 return this; 151 } 152 153 /** 154 * Specifies the failure message for tests that are expected to throw 155 * an exception but do not throw any. You can use a {@code %s} placeholder for 156 * the description of the expected exception. E.g. "Test doesn't throw %s." 157 * will fail with the error message 158 * "Test doesn't throw an instance of foo.". 159 * 160 * @param message exception detail message 161 * @return the rule itself 162 */ 163 public ExpectedException reportMissingExceptionWithMessage(String message) { 164 missingExceptionMessage = message; 165 return this; 166 } 167 168 public Statement apply(Statement base, 169 org.junit.runner.Description description) { 170 return new ExpectedExceptionStatement(base); 171 } 172 173 /** 174 * Verify that your code throws an exception that is matched by 175 * a Hamcrest matcher. 176 * <pre> @Test 177 * public void throwsExceptionThatCompliesWithMatcher() { 178 * NullPointerException e = new NullPointerException(); 179 * thrown.expect(is(e)); 180 * throw e; 181 * }</pre> 182 */ 183 public void expect(Matcher<?> matcher) { 184 matcherBuilder.add(matcher); 185 } 186 187 /** 188 * Verify that your code throws an exception that is an 189 * instance of specific {@code type}. 190 * <pre> @Test 191 * public void throwsExceptionWithSpecificType() { 192 * thrown.expect(NullPointerException.class); 193 * throw new NullPointerException(); 194 * }</pre> 195 */ 196 public void expect(Class<? extends Throwable> type) { 197 expect(instanceOf(type)); 198 } 199 200 /** 201 * Verify that your code throws an exception whose message contains 202 * a specific text. 203 * <pre> @Test 204 * public void throwsExceptionWhoseMessageContainsSpecificText() { 205 * thrown.expectMessage("happened"); 206 * throw new NullPointerException("What happened?"); 207 * }</pre> 208 */ 209 public void expectMessage(String substring) { 210 expectMessage(containsString(substring)); 211 } 212 213 /** 214 * Verify that your code throws an exception whose message is matched 215 * by a Hamcrest matcher. 216 * <pre> @Test 217 * public void throwsExceptionWhoseMessageCompliesWithMatcher() { 218 * thrown.expectMessage(startsWith("What")); 219 * throw new NullPointerException("What happened?"); 220 * }</pre> 221 */ 222 public void expectMessage(Matcher<String> matcher) { 223 expect(hasMessage(matcher)); 224 } 225 226 /** 227 * Verify that your code throws an exception whose cause is matched by 228 * a Hamcrest matcher. 229 * <pre> @Test 230 * public void throwsExceptionWhoseCauseCompliesWithMatcher() { 231 * NullPointerException expectedCause = new NullPointerException(); 232 * thrown.expectCause(is(expectedCause)); 233 * throw new IllegalArgumentException("What happened?", cause); 234 * }</pre> 235 */ 236 public void expectCause(Matcher<?> expectedCause) { 237 expect(hasCause(expectedCause)); 238 } 239 240 /** 241 * Check if any Exception is expected. 242 * @since 4.13 243 */ 244 public final boolean isAnyExceptionExpected() { 245 return matcherBuilder.expectsThrowable(); 246 } 247 248 private class ExpectedExceptionStatement extends Statement { 249 private final Statement next; 250 251 public ExpectedExceptionStatement(Statement base) { 252 next = base; 253 } 254 255 @Override 256 public void evaluate() throws Throwable { 257 try { 258 next.evaluate(); 259 } catch (Throwable e) { 260 handleException(e); 261 return; 262 } 263 if (isAnyExceptionExpected()) { 264 failDueToMissingException(); 265 } 266 } 267 } 268 269 private void handleException(Throwable e) throws Throwable { 270 if (isAnyExceptionExpected()) { 271 assertThat(e, matcherBuilder.build()); 272 } else { 273 throw e; 274 } 275 } 276 277 private void failDueToMissingException() throws AssertionError { 278 fail(missingExceptionMessage()); 279 } 280 281 private String missingExceptionMessage() { 282 String expectation= StringDescription.toString(matcherBuilder.build()); 283 return format(missingExceptionMessage, expectation); 284 } 285}