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