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 */ emptySuite()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 */ value()50 public Class<?>[] value(); 51 } 52 getAnnotatedClasses(Class<?> klass)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 */ Suite(Class<?> klass, RunnerBuilder builder)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 */ Suite(RunnerBuilder builder, Class<?>[] classes)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 */ Suite(Class<?> klass, Class<?>[] suiteClasses)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 */ Suite(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses)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 */ Suite(Class<?> klass, List<Runner> runners)111 protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError { 112 super(klass); 113 this.runners = Collections.unmodifiableList(runners); 114 } 115 116 @Override getChildren()117 protected List<Runner> getChildren() { 118 return runners; 119 } 120 121 @Override describeChild(Runner child)122 protected Description describeChild(Runner child) { 123 return child.getDescription(); 124 } 125 126 @Override runChild(Runner runner, final RunNotifier notifier)127 protected void runChild(Runner runner, final RunNotifier notifier) { 128 runner.run(notifier); 129 } 130 } 131