001package org.junit.runners; 002 003import java.lang.annotation.ElementType; 004import java.lang.annotation.Inherited; 005import java.lang.annotation.Retention; 006import java.lang.annotation.RetentionPolicy; 007import java.lang.annotation.Target; 008import java.util.List; 009 010import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; 011import org.junit.runner.Description; 012import org.junit.runner.Runner; 013import org.junit.runner.notification.RunNotifier; 014import org.junit.runners.model.InitializationError; 015import org.junit.runners.model.RunnerBuilder; 016 017/** 018 * Using <code>Suite</code> as a runner allows you to manually 019 * build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x 020 * static {@link junit.framework.Test} <code>suite()</code> method. To use it, annotate a class 021 * with <code>@RunWith(Suite.class)</code> and <code>@SuiteClasses({TestClass1.class, ...})</code>. 022 * When you run this class, it will run all the tests in all the suite classes. 023 * 024 * @since 4.0 025 */ 026public class Suite extends ParentRunner<Runner> { 027 /** 028 * Returns an empty suite. 029 */ 030 public static Runner emptySuite() { 031 try { 032 return new Suite((Class<?>) null, new Class<?>[0]); 033 } catch (InitializationError e) { 034 throw new RuntimeException("This shouldn't be possible"); 035 } 036 } 037 038 /** 039 * The <code>SuiteClasses</code> annotation specifies the classes to be run when a class 040 * annotated with <code>@RunWith(Suite.class)</code> is run. 041 */ 042 @Retention(RetentionPolicy.RUNTIME) 043 @Target(ElementType.TYPE) 044 @Inherited 045 public @interface SuiteClasses { 046 /** 047 * @return the classes to be run 048 */ 049 public Class<?>[] value(); 050 } 051 052 private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError { 053 SuiteClasses annotation = klass.getAnnotation(SuiteClasses.class); 054 if (annotation == null) { 055 throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName())); 056 } 057 return annotation.value(); 058 } 059 060 private final List<Runner> fRunners; 061 062 /** 063 * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code> 064 * 065 * @param klass the root class 066 * @param builder builds runners for classes in the suite 067 */ 068 public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError { 069 this(builder, klass, getAnnotatedClasses(klass)); 070 } 071 072 /** 073 * Call this when there is no single root class (for example, multiple class names 074 * passed on the command line to {@link org.junit.runner.JUnitCore} 075 * 076 * @param builder builds runners for classes in the suite 077 * @param classes the classes in the suite 078 */ 079 public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError { 080 this(null, builder.runners(null, classes)); 081 } 082 083 /** 084 * Call this when the default builder is good enough. Left in for compatibility with JUnit 4.4. 085 * 086 * @param klass the root of the suite 087 * @param suiteClasses the classes in the suite 088 */ 089 protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError { 090 this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses); 091 } 092 093 /** 094 * Called by this class and subclasses once the classes making up the suite have been determined 095 * 096 * @param builder builds runners for classes in the suite 097 * @param klass the root of the suite 098 * @param suiteClasses the classes in the suite 099 */ 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 */ 110 protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError { 111 super(klass); 112 fRunners = runners; 113 } 114 115 @Override 116 protected List<Runner> getChildren() { 117 return fRunners; 118 } 119 120 @Override 121 protected Description describeChild(Runner child) { 122 return child.getDescription(); 123 } 124 125 @Override 126 protected void runChild(Runner runner, final RunNotifier notifier) { 127 runner.run(notifier); 128 } 129}