001 package org.junit.rules;
002
003 import static java.lang.String.format;
004 import static org.hamcrest.CoreMatchers.containsString;
005 import static org.hamcrest.CoreMatchers.instanceOf;
006 import static org.junit.Assert.assertThat;
007 import static org.junit.Assert.fail;
008 import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
009 import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
010 import org.hamcrest.Matcher;
011 import org.hamcrest.StringDescription;
012 import org.junit.AssumptionViolatedException;
013 import 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 * @deprecated Since 4.13
110 * {@link org.junit.Assert#assertThrows(Class, org.junit.function.ThrowingRunnable)
111 * Assert.assertThrows} can be used to verify that your code throws a specific
112 * exception.
113 * @since 4.7
114 */
115 @Deprecated
116 public class ExpectedException implements TestRule {
117 /**
118 * Returns a {@linkplain TestRule rule} that expects no exception to
119 * be thrown (identical to behavior without this rule).
120 */
121 public static ExpectedException none() {
122 return new ExpectedException();
123 }
124
125 private final ExpectedExceptionMatcherBuilder matcherBuilder = new ExpectedExceptionMatcherBuilder();
126
127 private String missingExceptionMessage= "Expected test to throw %s";
128
129 private ExpectedException() {
130 }
131
132 /**
133 * This method does nothing. Don't use it.
134 * @deprecated AssertionErrors are handled by default since JUnit 4.12. Just
135 * like in JUnit <= 4.10.
136 */
137 @Deprecated
138 public ExpectedException handleAssertionErrors() {
139 return this;
140 }
141
142 /**
143 * This method does nothing. Don't use it.
144 * @deprecated AssumptionViolatedExceptions are handled by default since
145 * JUnit 4.12. Just like in JUnit <= 4.10.
146 */
147 @Deprecated
148 public ExpectedException handleAssumptionViolatedExceptions() {
149 return this;
150 }
151
152 /**
153 * Specifies the failure message for tests that are expected to throw
154 * an exception but do not throw any. You can use a {@code %s} placeholder for
155 * the description of the expected exception. E.g. "Test doesn't throw %s."
156 * will fail with the error message
157 * "Test doesn't throw an instance of foo.".
158 *
159 * @param message exception detail message
160 * @return the rule itself
161 */
162 public ExpectedException reportMissingExceptionWithMessage(String message) {
163 missingExceptionMessage = message;
164 return this;
165 }
166
167 public Statement apply(Statement base,
168 org.junit.runner.Description description) {
169 return new ExpectedExceptionStatement(base);
170 }
171
172 /**
173 * Verify that your code throws an exception that is matched by
174 * a Hamcrest matcher.
175 * <pre> @Test
176 * public void throwsExceptionThatCompliesWithMatcher() {
177 * NullPointerException e = new NullPointerException();
178 * thrown.expect(is(e));
179 * throw e;
180 * }</pre>
181 *
182 * @deprecated use {@code org.hamcrest.junit.ExpectedException.expect()}
183 */
184 @Deprecated
185 public void expect(Matcher<?> matcher) {
186 matcherBuilder.add(matcher);
187 }
188
189 /**
190 * Verify that your code throws an exception that is an
191 * instance of specific {@code type}.
192 * <pre> @Test
193 * public void throwsExceptionWithSpecificType() {
194 * thrown.expect(NullPointerException.class);
195 * throw new NullPointerException();
196 * }</pre>
197 */
198 public void expect(Class<? extends Throwable> type) {
199 expect(instanceOf(type));
200 }
201
202 /**
203 * Verify that your code throws an exception whose message contains
204 * a specific text.
205 * <pre> @Test
206 * public void throwsExceptionWhoseMessageContainsSpecificText() {
207 * thrown.expectMessage("happened");
208 * throw new NullPointerException("What happened?");
209 * }</pre>
210 */
211 public void expectMessage(String substring) {
212 expectMessage(containsString(substring));
213 }
214
215 /**
216 * Verify that your code throws an exception whose message is matched
217 * by a Hamcrest matcher.
218 * <pre> @Test
219 * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
220 * thrown.expectMessage(startsWith("What"));
221 * throw new NullPointerException("What happened?");
222 * }</pre>
223 *
224 * @deprecated use {@code org.hamcrest.junit.ExpectedException.expectMessage()}
225 */
226 @Deprecated
227 public void expectMessage(Matcher<String> matcher) {
228 expect(hasMessage(matcher));
229 }
230
231 /**
232 * Verify that your code throws an exception whose cause is matched by
233 * a Hamcrest matcher.
234 * <pre> @Test
235 * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
236 * NullPointerException expectedCause = new NullPointerException();
237 * thrown.expectCause(is(expectedCause));
238 * throw new IllegalArgumentException("What happened?", cause);
239 * }</pre>
240 *
241 * @deprecated use {@code org.hamcrest.junit.ExpectedException.expectCause()}
242 */
243 @Deprecated
244 public void expectCause(Matcher<?> expectedCause) {
245 expect(hasCause(expectedCause));
246 }
247
248 /**
249 * Check if any Exception is expected.
250 * @since 4.13
251 */
252 public final boolean isAnyExceptionExpected() {
253 return matcherBuilder.expectsThrowable();
254 }
255
256 private class ExpectedExceptionStatement extends Statement {
257 private final Statement next;
258
259 public ExpectedExceptionStatement(Statement base) {
260 next = base;
261 }
262
263 @Override
264 public void evaluate() throws Throwable {
265 try {
266 next.evaluate();
267 } catch (Throwable e) {
268 handleException(e);
269 return;
270 }
271 if (isAnyExceptionExpected()) {
272 failDueToMissingException();
273 }
274 }
275 }
276
277 private void handleException(Throwable e) throws Throwable {
278 if (isAnyExceptionExpected()) {
279 assertThat(e, matcherBuilder.build());
280 } else {
281 throw e;
282 }
283 }
284
285 private void failDueToMissingException() throws AssertionError {
286 fail(missingExceptionMessage());
287 }
288
289 private String missingExceptionMessage() {
290 String expectation= StringDescription.toString(matcherBuilder.build());
291 return format(missingExceptionMessage, expectation);
292 }
293 }