View Javadoc
1   package org.junit.runners;
2   
3   import java.lang.annotation.ElementType;
4   import java.lang.annotation.Inherited;
5   import java.lang.annotation.Retention;
6   import java.lang.annotation.RetentionPolicy;
7   import java.lang.annotation.Target;
8   import java.util.Collections;
9   import java.util.List;
10  
11  import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
12  import org.junit.runner.Description;
13  import org.junit.runner.Runner;
14  import org.junit.runner.notification.RunNotifier;
15  import org.junit.runners.model.InitializationError;
16  import org.junit.runners.model.RunnerBuilder;
17  
18  /**
19   * Using <code>Suite</code> as a runner allows you to manually
20   * build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x
21   * static {@link junit.framework.Test} <code>suite()</code> method. To use it, annotate a class
22   * with <code>@RunWith(Suite.class)</code> and <code>@SuiteClasses({TestClass1.class, ...})</code>.
23   * When you run this class, it will run all the tests in all the suite classes.
24   *
25   * @since 4.0
26   */
27  public class Suite extends ParentRunner<Runner> {
28      /**
29       * Returns an empty suite.
30       */
31      public static Runner emptySuite() {
32          try {
33              return new Suite((Class<?>) null, new Class<?>[0]);
34          } catch (InitializationError e) {
35              throw new RuntimeException("This shouldn't be possible");
36          }
37      }
38  
39      /**
40       * The <code>SuiteClasses</code> annotation specifies the classes to be run when a class
41       * annotated with <code>@RunWith(Suite.class)</code> is run.
42       */
43      @Retention(RetentionPolicy.RUNTIME)
44      @Target(ElementType.TYPE)
45      @Inherited
46      public @interface SuiteClasses {
47          /**
48           * @return the classes to be run
49           */
50          public Class<?>[] value();
51      }
52  
53      private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
54          SuiteClasses annotation = klass.getAnnotation(SuiteClasses.class);
55          if (annotation == null) {
56              throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName()));
57          }
58          return annotation.value();
59      }
60  
61      private final List<Runner> runners;
62  
63      /**
64       * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code>
65       *
66       * @param klass the root class
67       * @param builder builds runners for classes in the suite
68       */
69      public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
70          this(builder, klass, getAnnotatedClasses(klass));
71      }
72  
73      /**
74       * Call this when there is no single root class (for example, multiple class names
75       * passed on the command line to {@link org.junit.runner.JUnitCore}
76       *
77       * @param builder builds runners for classes in the suite
78       * @param classes the classes in the suite
79       */
80      public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
81          this(null, builder.runners(null, classes));
82      }
83  
84      /**
85       * Call this when the default builder is good enough. Left in for compatibility with JUnit 4.4.
86       *
87       * @param klass the root of the suite
88       * @param suiteClasses the classes in the suite
89       */
90      protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
91          this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses);
92      }
93  
94      /**
95       * Called by this class and subclasses once the classes making up the suite have been determined
96       *
97       * @param builder builds runners for classes in the suite
98       * @param klass the root of the suite
99       * @param suiteClasses the classes in the suite
100      */
101     protected Suite(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
102         this(klass, builder.runners(klass, suiteClasses));
103     }
104 
105     /**
106      * Called by this class and subclasses once the runners making up the suite have been determined
107      *
108      * @param klass root of the suite
109      * @param runners for each class in the suite, a {@link Runner}
110      */
111     protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
112         super(klass);
113         this.runners = Collections.unmodifiableList(runners);
114     }
115 
116     @Override
117     protected List<Runner> getChildren() {
118         return runners;
119     }
120 
121     @Override
122     protected Description describeChild(Runner child) {
123         return child.getDescription();
124     }
125 
126     @Override
127     protected void runChild(Runner runner, final RunNotifier notifier) {
128         runner.run(notifier);
129     }
130 }