• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.junit.rules;
2 
3 import static java.lang.String.format;
4 import static org.hamcrest.CoreMatchers.containsString;
5 import static org.hamcrest.CoreMatchers.instanceOf;
6 import static org.junit.Assert.assertThat;
7 import static org.junit.Assert.fail;
8 import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
9 import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
10 import org.hamcrest.Matcher;
11 import org.hamcrest.StringDescription;
12 import org.junit.AssumptionViolatedException;
13 import org.junit.runners.model.Statement;
14 
15 /**
16  * The {@code ExpectedException} rule allows you to verify that your code
17  * throws a specific exception.
18  *
19  * <h3>Usage</h3>
20  *
21  * <pre> public class SimpleExpectedExceptionTest {
22  *     &#064;Rule
23  *     public ExpectedException thrown = ExpectedException.none();
24  *
25  *     &#064;Test
26  *     public void throwsNothing() {
27  *         // no exception expected, none thrown: passes.
28  *     }
29  *
30  *     &#064;Test
31  *     public void throwsExceptionWithSpecificType() {
32  *         thrown.expect(NullPointerException.class);
33  *         throw new NullPointerException();
34  *     }
35  * }</pre>
36  *
37  * <p>You have to add the {@code ExpectedException} rule to your test.
38  * This doesn't affect your existing tests (see {@code throwsNothing()}).
39  * After specifying the type of the expected exception your test is
40  * successful when such an exception is thrown and it fails if a
41  * different or no exception is thrown.
42  *
43  * <p>This rule does not perform any special magic to make execution continue
44  * as if the exception had not been thrown. So it is nearly always a mistake
45  * for a test method to have statements after the one that is expected to
46  * throw the exception.
47  *
48  * <p>Instead of specifying the exception's type you can characterize the
49  * expected exception based on other criteria, too:
50  *
51  * <ul>
52  *   <li>The exception's message contains a specific text: {@link #expectMessage(String)}</li>
53  *   <li>The exception's message complies with a Hamcrest matcher: {@link #expectMessage(Matcher)}</li>
54  *   <li>The exception's cause complies with a Hamcrest matcher: {@link #expectCause(Matcher)}</li>
55  *   <li>The exception itself complies with a Hamcrest matcher: {@link #expect(Matcher)}</li>
56  * </ul>
57  *
58  * <p>You can combine any of the presented expect-methods. The test is
59  * successful if all specifications are met.
60  * <pre> &#064;Test
61  * public void throwsException() {
62  *     thrown.expect(NullPointerException.class);
63  *     thrown.expectMessage(&quot;happened&quot;);
64  *     throw new NullPointerException(&quot;What happened?&quot;);
65  * }</pre>
66  *
67  * <p>It is recommended to set the {@link org.junit.Rule#order() order} of the
68  * {@code ExpectedException} to {@code Integer.MAX_VALUE} if it is used together
69  * with another rule that handles exceptions, e.g. {@link ErrorCollector}.
70  * Otherwise failing tests may be successful.
71  * <pre> &#064;Rule(order = Integer.MAX_VALUE)
72  * public ExpectedException thrown = ExpectedException.none();</pre>
73  *
74  * <h3>AssumptionViolatedExceptions</h3>
75  * <p>JUnit uses {@link AssumptionViolatedException}s for indicating that a test
76  * provides no useful information. (See {@link org.junit.Assume} for more
77  * information.) You have to call {@code assume} methods before you set
78  * expectations of the {@code ExpectedException} rule. In this case the rule
79  * will not handle consume the exceptions and it can be handled by the
80  * framework. E.g. the following test is ignored by JUnit's default runner.
81  *
82  * <pre> &#064;Test
83  * public void ignoredBecauseOfFailedAssumption() {
84  *     assumeTrue(false); // throws AssumptionViolatedException
85  *     thrown.expect(NullPointerException.class);
86  * }</pre>
87  *
88  * <h3>AssertionErrors</h3>
89  *
90  * <p>JUnit uses {@link AssertionError}s for indicating that a test is failing. You
91  * have to call {@code assert} methods before you set expectations of the
92  * {@code ExpectedException} rule, if they should be handled by the framework.
93  * E.g. the following test fails because of the {@code assertTrue} statement.
94  *
95  * <pre> &#064;Test
96  * public void throwsUnhandled() {
97  *     assertTrue(false); // throws AssertionError
98  *     thrown.expect(NullPointerException.class);
99  * }</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
none()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 
ExpectedException()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 &lt;= 4.10.
137      */
138     @Deprecated
handleAssertionErrors()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 &lt;= 4.10.
147      */
148     @Deprecated
handleAssumptionViolatedExceptions()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      */
reportMissingExceptionWithMessage(String message)163     public ExpectedException reportMissingExceptionWithMessage(String message) {
164         missingExceptionMessage = message;
165         return this;
166     }
167 
apply(Statement base, org.junit.runner.Description description)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> &#064;Test
177      * public void throwsExceptionThatCompliesWithMatcher() {
178      *     NullPointerException e = new NullPointerException();
179      *     thrown.expect(is(e));
180      *     throw e;
181      * }</pre>
182      */
expect(Matcher<?> matcher)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> &#064;Test
191      * public void throwsExceptionWithSpecificType() {
192      *     thrown.expect(NullPointerException.class);
193      *     throw new NullPointerException();
194      * }</pre>
195      */
expect(Class<? extends Throwable> type)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> &#064;Test
204      * public void throwsExceptionWhoseMessageContainsSpecificText() {
205      *     thrown.expectMessage(&quot;happened&quot;);
206      *     throw new NullPointerException(&quot;What happened?&quot;);
207      * }</pre>
208      */
expectMessage(String substring)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> &#064;Test
217      * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
218      *     thrown.expectMessage(startsWith(&quot;What&quot;));
219      *     throw new NullPointerException(&quot;What happened?&quot;);
220      * }</pre>
221      */
expectMessage(Matcher<String> matcher)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> &#064;Test
230      * public void throwsExceptionWhoseCauseCompliesWithMatcher() {
231      *     NullPointerException expectedCause = new NullPointerException();
232      *     thrown.expectCause(is(expectedCause));
233      *     throw new IllegalArgumentException(&quot;What happened?&quot;, cause);
234      * }</pre>
235      */
expectCause(Matcher<?> expectedCause)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      */
isAnyExceptionExpected()244     public final boolean isAnyExceptionExpected() {
245         return matcherBuilder.expectsThrowable();
246     }
247 
248     private class ExpectedExceptionStatement extends Statement {
249         private final Statement next;
250 
ExpectedExceptionStatement(Statement base)251         public ExpectedExceptionStatement(Statement base) {
252             next = base;
253         }
254 
255         @Override
evaluate()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 
handleException(Throwable e)269     private void handleException(Throwable e) throws Throwable {
270         if (isAnyExceptionExpected()) {
271             assertThat(e, matcherBuilder.build());
272         } else {
273             throw e;
274         }
275     }
276 
failDueToMissingException()277     private void failDueToMissingException() throws AssertionError {
278         fail(missingExceptionMessage());
279     }
280 
missingExceptionMessage()281     private String missingExceptionMessage() {
282         String expectation= StringDescription.toString(matcherBuilder.build());
283         return format(missingExceptionMessage, expectation);
284     }
285 }
286