1 package org.junit.runner;
2
3 import java.util.Comparator;
4
5 import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
6 import org.junit.internal.requests.ClassRequest;
7 import org.junit.internal.requests.FilterRequest;
8 import org.junit.internal.requests.SortingRequest;
9 import org.junit.internal.runners.ErrorReportingRunner;
10 import org.junit.runner.manipulation.Filter;
11 import org.junit.runners.model.InitializationError;
12
13 /**
14 * A <code>Request</code> is an abstract description of tests to be run. Older versions of
15 * JUnit did not need such a concept--tests to be run were described either by classes containing
16 * tests or a tree of {@link org.junit.Test}s. However, we want to support filtering and sorting,
17 * so we need a more abstract specification than the tests themselves and a richer
18 * specification than just the classes.
19 *
20 * <p>The flow when JUnit runs tests is that a <code>Request</code> specifies some tests to be run ->
21 * a {@link org.junit.runner.Runner} is created for each class implied by the <code>Request</code> ->
22 * the {@link org.junit.runner.Runner} returns a detailed {@link org.junit.runner.Description}
23 * which is a tree structure of the tests to be run.
24 *
25 * @since 4.0
26 */
27 public abstract class Request {
28 /**
29 * Create a <code>Request</code> that, when processed, will run a single test.
30 * This is done by filtering out all other tests. This method is used to support rerunning
31 * single tests.
32 *
33 * @param clazz the class of the test
34 * @param methodName the name of the test
35 * @return a <code>Request</code> that will cause a single test be run
36 */
37 public static Request method(Class<?> clazz, String methodName) {
38 Description method = Description.createTestDescription(clazz, methodName);
39 return Request.aClass(clazz).filterWith(method);
40 }
41
42 /**
43 * Create a <code>Request</code> that, when processed, will run all the tests
44 * in a class. The odd name is necessary because <code>class</code> is a reserved word.
45 *
46 * @param clazz the class containing the tests
47 * @return a <code>Request</code> that will cause all tests in the class to be run
48 */
49 public static Request aClass(Class<?> clazz) {
50 return new ClassRequest(clazz);
51 }
52
53 /**
54 * Create a <code>Request</code> that, when processed, will run all the tests
55 * in a class. If the class has a suite() method, it will be ignored.
56 *
57 * @param clazz the class containing the tests
58 * @return a <code>Request</code> that will cause all tests in the class to be run
59 */
60 public static Request classWithoutSuiteMethod(Class<?> clazz) {
61 return new ClassRequest(clazz, false);
62 }
63
64 /**
65 * Create a <code>Request</code> that, when processed, will run all the tests
66 * in a set of classes.
67 *
68 * @param computer Helps construct Runners from classes
69 * @param classes the classes containing the tests
70 * @return a <code>Request</code> that will cause all tests in the classes to be run
71 */
72 public static Request classes(Computer computer, Class<?>... classes) {
73 try {
74 AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true);
75 Runner suite = computer.getSuite(builder, classes);
76 return runner(suite);
77 } catch (InitializationError e) {
78 throw new RuntimeException(
79 "Bug in saff's brain: Suite constructor, called as above, should always complete");
80 }
81 }
82
83 /**
84 * Create a <code>Request</code> that, when processed, will run all the tests
85 * in a set of classes with the default <code>Computer</code>.
86 *
87 * @param classes the classes containing the tests
88 * @return a <code>Request</code> that will cause all tests in the classes to be run
89 */
90 public static Request classes(Class<?>... classes) {
91 return classes(JUnitCore.defaultComputer(), classes);
92 }
93
94
95 /**
96 * Creates a {@link Request} that, when processed, will report an error for the given
97 * test class with the given cause.
98 */
99 public static Request errorReport(Class<?> klass, Throwable cause) {
100 return runner(new ErrorReportingRunner(klass, cause));
101 }
102
103 /**
104 * @param runner the runner to return
105 * @return a <code>Request</code> that will run the given runner when invoked
106 */
107 public static Request runner(final Runner runner) {
108 return new Request() {
109 @Override
110 public Runner getRunner() {
111 return runner;
112 }
113 };
114 }
115
116 /**
117 * Returns a {@link Runner} for this Request
118 *
119 * @return corresponding {@link Runner} for this Request
120 */
121 public abstract Runner getRunner();
122
123 /**
124 * Returns a Request that only contains those tests that should run when
125 * <code>filter</code> is applied
126 *
127 * @param filter The {@link Filter} to apply to this Request
128 * @return the filtered Request
129 */
130 public Request filterWith(Filter filter) {
131 return new FilterRequest(this, filter);
132 }
133
134 /**
135 * Returns a Request that only runs contains tests whose {@link Description}
136 * equals <code>desiredDescription</code>
137 *
138 * @param desiredDescription {@link Description} of those tests that should be run
139 * @return the filtered Request
140 */
141 public Request filterWith(final Description desiredDescription) {
142 return filterWith(Filter.matchMethodDescription(desiredDescription));
143 }
144
145 /**
146 * Returns a Request whose Tests can be run in a certain order, defined by
147 * <code>comparator</code>
148 * <p>
149 * For example, here is code to run a test suite in alphabetical order:
150 * <pre>
151 * private static Comparator<Description> forward() {
152 * return new Comparator<Description>() {
153 * public int compare(Description o1, Description o2) {
154 * return o1.getDisplayName().compareTo(o2.getDisplayName());
155 * }
156 * };
157 * }
158 *
159 * public static main() {
160 * new JUnitCore().run(Request.aClass(AllTests.class).sortWith(forward()));
161 * }
162 * </pre>
163 *
164 * @param comparator definition of the order of the tests in this Request
165 * @return a Request with ordered Tests
166 */
167 public Request sortWith(Comparator<Description> comparator) {
168 return new SortingRequest(this, comparator);
169 }
170 }