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 * @since 4.7
110 */
111 public 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 }