    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     *     &#064;Rule
    023     *     public ExpectedException thrown = ExpectedException.none();
    024     *
    025     *     &#064;Test
    026     *     public void throwsNothing() {
    027     *         // no exception expected, none thrown: passes.
    028     *     }
    029     *
    030     *     &#064;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> &#064;Test
    061     * public void throwsException() {
    062     *     thrown.expect(NullPointerException.class);
    063     *     thrown.expectMessage(&quot;happened&quot;);
    064     *     throw new NullPointerException(&quot;What happened?&quot;);
    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> &#064;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> &#064;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> &#064;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 &lt;= 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 &lt;= 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> &#064;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> &#064;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> &#064;Test
    204         * public void throwsExceptionWhoseMessageContainsSpecificText() {
    205         *     thrown.expectMessage(&quot;happened&quot;);
    206         *     throw new NullPointerException(&quot;What happened?&quot;);
    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> &#064;Test
    217         * public void throwsExceptionWhoseMessageCompliesWithMatcher() {
    218         *     thrown.expectMessage(startsWith(&quot;What&quot;));
    219         *     throw new NullPointerException(&quot;What happened?&quot;);
    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> &#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         */
    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    }