• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.junit.rules;
2 
3 import static org.hamcrest.CoreMatchers.instanceOf;
4 import static org.junit.matchers.JUnitMatchers.both;
5 import static org.junit.matchers.JUnitMatchers.containsString;
6 import org.hamcrest.Description;
7 import org.hamcrest.Matcher;
8 import org.hamcrest.StringDescription;
9 import org.junit.Assert;
10 import org.junit.internal.matchers.TypeSafeMatcher;
11 import org.junit.runners.model.Statement;
12 
13 /**
14  * The ExpectedException Rule allows in-test specification of expected exception
15  * types and messages:
16  *
17  * <pre>
18  * // These tests all pass.
19  * public static class HasExpectedException {
20  * 	&#064;Rule
21  * 	public ExpectedException thrown= ExpectedException.none();
22  *
23  * 	&#064;Test
24  * 	public void throwsNothing() {
25  *    // no exception expected, none thrown: passes.
26  * 	}
27  *
28  * 	&#064;Test
29  * 	public void throwsNullPointerException() {
30  * 		thrown.expect(NullPointerException.class);
31  * 		throw new NullPointerException();
32  * 	}
33  *
34  * 	&#064;Test
35  * 	public void throwsNullPointerExceptionWithMessage() {
36  * 		thrown.expect(NullPointerException.class);
37  * 		thrown.expectMessage(&quot;happened?&quot;);
38  * 		thrown.expectMessage(startsWith(&quot;What&quot;));
39  * 		throw new NullPointerException(&quot;What happened?&quot;);
40  * 	}
41  * }
42  * </pre>
43  */
44 public class ExpectedException implements TestRule {
45 	/**
46 	 * @return a Rule that expects no exception to be thrown
47 	 * (identical to behavior without this Rule)
48 	 */
none()49 	public static ExpectedException none() {
50 		return new ExpectedException();
51 	}
52 
53 	private Matcher<Object> fMatcher= null;
54 
ExpectedException()55 	private ExpectedException() {
56 
57 	}
58 
apply(Statement base, org.junit.runner.Description description)59 	public Statement apply(Statement base,
60 			org.junit.runner.Description description) {
61 		return new ExpectedExceptionStatement(base);
62 	}
63 
64 	/**
65 	 * Adds {@code matcher} to the list of requirements for any thrown exception.
66 	 */
67 	// Should be able to remove this suppression in some brave new hamcrest world.
68 	@SuppressWarnings("unchecked")
expect(Matcher<?> matcher)69 	public void expect(Matcher<?> matcher) {
70 		if (fMatcher == null)
71 			fMatcher= (Matcher<Object>) matcher;
72 		else
73 			fMatcher= both(fMatcher).and(matcher);
74 	}
75 
76 	/**
77 	 * Adds to the list of requirements for any thrown exception that it
78 	 * should be an instance of {@code type}
79 	 */
expect(Class<? extends Throwable> type)80 	public void expect(Class<? extends Throwable> type) {
81 		expect(instanceOf(type));
82 	}
83 
84 	/**
85 	 * Adds to the list of requirements for any thrown exception that it
86 	 * should <em>contain</em> string {@code substring}
87 	 */
expectMessage(String substring)88 	public void expectMessage(String substring) {
89 		expectMessage(containsString(substring));
90 	}
91 
92 	/**
93 	 * Adds {@code matcher} to the list of requirements for the message
94 	 * returned from any thrown exception.
95 	 */
expectMessage(Matcher<String> matcher)96 	public void expectMessage(Matcher<String> matcher) {
97 		expect(hasMessage(matcher));
98 	}
99 
100 	private class ExpectedExceptionStatement extends Statement {
101 		private final Statement fNext;
102 
ExpectedExceptionStatement(Statement base)103 		public ExpectedExceptionStatement(Statement base) {
104 			fNext= base;
105 		}
106 
107 		@Override
evaluate()108 		public void evaluate() throws Throwable {
109 			try {
110 				fNext.evaluate();
111 			} catch (Throwable e) {
112 				if (fMatcher == null)
113 					throw e;
114 				Assert.assertThat(e, fMatcher);
115 				return;
116 			}
117 			if (fMatcher != null)
118 				throw new AssertionError("Expected test to throw "
119 						+ StringDescription.toString(fMatcher));
120 		}
121 	}
122 
hasMessage(final Matcher<String> matcher)123 	private Matcher<Throwable> hasMessage(final Matcher<String> matcher) {
124 		return new TypeSafeMatcher<Throwable>() {
125 			public void describeTo(Description description) {
126 				description.appendText("exception with message ");
127 				description.appendDescriptionOf(matcher);
128 			}
129 
130 			@Override
131 			public boolean matchesSafely(Throwable item) {
132 				return matcher.matches(item.getMessage());
133 			}
134 		};
135 	}
136 }
137