Save This Page
Home » GWT-2009.11.30 » junit » framework » [javadoc | source]
    1   package junit.framework;
    2   
    3   import java.io.PrintWriter;
    4   import java.io.StringWriter;
    5   import java.lang.reflect.Constructor;
    6   import java.lang.reflect.InvocationTargetException;
    7   import java.lang.reflect.Method;
    8   import java.lang.reflect.Modifier;
    9   import java.util.ArrayList;
   10   import java.util.Enumeration;
   11   import java.util.List;
   12   import java.util.Vector;
   13   
   14   /**
   15    * <p>A <code>TestSuite</code> is a <code>Composite</code> of Tests.
   16    * It runs a collection of test cases. Here is an example using
   17    * the dynamic test definition.
   18    * <pre>
   19    * TestSuite suite= new TestSuite();
   20    * suite.addTest(new MathTest("testAdd"));
   21    * suite.addTest(new MathTest("testDivideByZero"));
   22    * </pre>
   23    * </p>
   24    * 
   25    * <p>Alternatively, a TestSuite can extract the tests to be run automatically.
   26    * To do so you pass the class of your TestCase class to the
   27    * TestSuite constructor.
   28    * <pre>
   29    * TestSuite suite= new TestSuite(MathTest.class);
   30    * </pre>
   31    * </p>
   32    * 
   33    * <p>This constructor creates a suite with all the methods
   34    * starting with "test" that take no arguments.</p>
   35    * 
   36    * <p>A final option is to do the same for a large array of test classes.
   37    * <pre>
   38    * Class[] testClasses = { MathTest.class, AnotherTest.class }
   39    * TestSuite suite= new TestSuite(testClasses);
   40    * </pre>
   41    * </p>
   42    *
   43    * @see Test
   44    */
   45   public class TestSuite implements Test {
   46   
   47   	/**
   48   	 * ...as the moon sets over the early morning Merlin, Oregon
   49   	 * mountains, our intrepid adventurers type...
   50   	 */
   51   	static public Test createTest(Class<? extends TestCase> theClass, String name) {
   52   		Constructor<? extends TestCase> constructor;
   53   		try {
   54   			constructor= getTestConstructor(theClass);
   55   		} catch (NoSuchMethodException e) {
   56   			return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()");
   57   		}
   58   		Object test;
   59   		try {
   60   			if (constructor.getParameterTypes().length == 0) {
   61   				test= constructor.newInstance(new Object[0]);
   62   				if (test instanceof TestCase)
   63   					((TestCase) test).setName(name);
   64   			} else {
   65   				test= constructor.newInstance(new Object[]{name});
   66   			}
   67   		} catch (InstantiationException e) {
   68   			return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
   69   		} catch (InvocationTargetException e) {
   70   			return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
   71   		} catch (IllegalAccessException e) {
   72   			return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
   73   		}
   74   		return (Test) test;
   75   	}
   76   	
   77   	/**
   78   	 * Gets a constructor which takes a single String as
   79   	 * its argument or a no arg constructor.
   80   	 */
   81   	public static Constructor<? extends TestCase> getTestConstructor(Class<? extends TestCase> theClass) throws NoSuchMethodException {
   82   		try {
   83   			return theClass.getConstructor(String.class);	
   84   		} catch (NoSuchMethodException e) {
   85   			// fall through
   86   		}
   87   		return theClass.getConstructor(new Class[0]);
   88   	}
   89   
   90   	/**
   91   	 * Returns a test which will fail and log a warning message.
   92   	 */
   93   	public static Test warning(final String message) {
   94   		return new TestCase("warning") {
   95   			@Override
   96   			protected void runTest() {
   97   				fail(message);
   98   			}
   99   		};
  100   	}
  101   
  102   	/**
  103   	 * Converts the stack trace into a string
  104   	 */
  105   	private static String exceptionToString(Throwable t) {
  106   		StringWriter stringWriter= new StringWriter();
  107   		PrintWriter writer= new PrintWriter(stringWriter);
  108   		t.printStackTrace(writer);
  109   		return stringWriter.toString();
  110   	}
  111   	
  112   	private String fName;
  113   
  114   	private Vector<Test> fTests= new Vector<Test>(10); // Cannot convert this to List because it is used directly by some test runners
  115   
  116       /**
  117   	 * Constructs an empty TestSuite.
  118   	 */
  119   	public TestSuite() {
  120   	}
  121   	
  122   	/**
  123   	 * Constructs a TestSuite from the given class. Adds all the methods
  124   	 * starting with "test" as test cases to the suite.
  125   	 * Parts of this method were written at 2337 meters in the Hueffihuette,
  126   	 * Kanton Uri
  127   	 */
  128   	 public TestSuite(final Class<? extends TestCase> theClass) {
  129   		fName= theClass.getName();
  130   		try {
  131   			getTestConstructor(theClass); // Avoid generating multiple error messages
  132   		} catch (NoSuchMethodException e) {
  133   			addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"));
  134   			return;
  135   		}
  136   
  137   		if (!Modifier.isPublic(theClass.getModifiers())) {
  138   			addTest(warning("Class "+theClass.getName()+" is not public"));
  139   			return;
  140   		}
  141   
  142   		Class<?> superClass= theClass;
  143   		List<String> names= new ArrayList<String>();
  144   		while (Test.class.isAssignableFrom(superClass)) {
  145   			for (Method each : superClass.getDeclaredMethods())
  146   				addTestMethod(each, names, theClass);
  147   			superClass= superClass.getSuperclass();
  148   		}
  149   		if (fTests.size() == 0)
  150   			addTest(warning("No tests found in "+theClass.getName()));
  151   	}
  152   	
  153   	/**
  154   	 * Constructs a TestSuite from the given class with the given name.
  155   	 * @see TestSuite#TestSuite(Class)
  156   	 */
  157   	public TestSuite(Class<? extends TestCase>  theClass, String name) {
  158   		this(theClass);
  159   		setName(name);
  160   	}
  161   	
  162      	/**
  163   	 * Constructs an empty TestSuite.
  164   	 */
  165   	public TestSuite(String name) {
  166   		setName(name);
  167   	}
  168   	
  169   	/**
  170   	 * Constructs a TestSuite from the given array of classes.  
  171   	 * @param classes {@link TestCase}s
  172   	 */
  173   	public TestSuite (Class<?>... classes) {
  174   		for (Class<?> each : classes)
  175   			addTest(new TestSuite(each.asSubclass(TestCase.class)));
  176   	}
  177   	
  178   	/**
  179   	 * Constructs a TestSuite from the given array of classes with the given name.
  180   	 * @see TestSuite#TestSuite(Class[])
  181   	 */
  182   	public TestSuite(Class<? extends TestCase>[] classes, String name) {
  183   		this(classes);
  184   		setName(name);
  185   	}
  186   	
  187   	/**
  188   	 * Adds a test to the suite.
  189   	 */
  190   	public void addTest(Test test) {
  191   		fTests.add(test);
  192   	}
  193   
  194   	/**
  195   	 * Adds the tests from the given class to the suite
  196   	 */
  197   	public void addTestSuite(Class<? extends TestCase> testClass) {
  198   		addTest(new TestSuite(testClass));
  199   	}
  200   	
  201   	/**
  202   	 * Counts the number of test cases that will be run by this test.
  203   	 */
  204   	public int countTestCases() {
  205   		int count= 0;
  206   		for (Test each : fTests)
  207   			count+=  each.countTestCases();
  208   		return count;
  209   	}
  210   
  211   	/**
  212   	 * Returns the name of the suite. Not all
  213   	 * test suites have a name and this method
  214   	 * can return null.
  215   	 */
  216   	public String getName() {
  217   		return fName;
  218   	}
  219   	 
  220   	/**
  221   	 * Runs the tests and collects their result in a TestResult.
  222   	 */
  223   	public void run(TestResult result) {
  224   		for (Test each : fTests) {
  225   	  		if (result.shouldStop() )
  226   	  			break;
  227   			runTest(each, result);
  228   		}
  229   	}
  230   
  231   	public void runTest(Test test, TestResult result) {
  232   		test.run(result);
  233   	}
  234   	 
  235   	/**
  236   	 * Sets the name of the suite.
  237   	 * @param name the name to set
  238   	 */
  239   	public void setName(String name) {
  240   		fName= name;
  241   	}
  242   
  243   	/**
  244   	 * Returns the test at the given index
  245   	 */
  246   	public Test testAt(int index) {
  247   		return fTests.get(index);
  248   	}
  249   	
  250   	/**
  251   	 * Returns the number of tests in this suite
  252   	 */
  253   	public int testCount() {
  254   		return fTests.size();
  255   	}
  256   	
  257   	/**
  258   	 * Returns the tests as an enumeration
  259   	 */
  260   	public Enumeration<Test> tests() {
  261   		return fTests.elements();
  262   	}
  263   	
  264   	/**
  265   	 */
  266   	@Override
  267   	public String toString() {
  268   		if (getName() != null)
  269   			return getName();
  270   		return super.toString();
  271   	 }
  272   
  273   	private void addTestMethod(Method m, List<String> names, Class<? extends TestCase> theClass) {
  274   		String name= m.getName();
  275   		if (names.contains(name))
  276   			return;
  277   		if (! isPublicTestMethod(m)) {
  278   			if (isTestMethod(m))
  279   				addTest(warning("Test method isn't public: "+ m.getName() + "(" + theClass.getCanonicalName() + ")"));
  280   			return;
  281   		}
  282   		names.add(name);
  283   		addTest(createTest(theClass, name));
  284   	}
  285   
  286   	private boolean isPublicTestMethod(Method m) {
  287   		return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
  288   	 }
  289   	 
  290   	private boolean isTestMethod(Method m) {
  291   		return 
  292   			m.getParameterTypes().length == 0 && 
  293   			m.getName().startsWith("test") && 
  294   			m.getReturnType().equals(Void.TYPE);
  295   	 }
  296   }

Save This Page
Home » GWT-2009.11.30 » junit » framework » [javadoc | source]