Home » displaytag-1.1.1-src » org » displaytag » test » [javadoc | source]

    1   package org.displaytag.test;
    2   
    3   import java.io.File;
    4   import java.lang.reflect.Method;
    5   import java.lang.reflect.Modifier;
    6   import java.net.URL;
    7   import java.net.URLDecoder;
    8   import java.util.ArrayList;
    9   import java.util.Iterator;
   10   import java.util.List;
   11   
   12   import junit.framework.Test;
   13   import junit.framework.TestCase;
   14   import junit.framework.TestSuite;
   15   
   16   import org.apache.commons.logging.Log;
   17   import org.apache.commons.logging.LogFactory;
   18   
   19   
   20   /**
   21    * Dynamic test suite derived from http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit.html. Runs all Java test
   22    * cases in the source tree that extend TestCase. This helps running tests faster with ant/maven since httpunit tests
   23    * requires forking and starting a new java process for each test is too slow.
   24    * @author Fabrizio Giustina
   25    * @version $Revision: 902 $ ($Author: fgiust $)
   26    */
   27   public class TestAll extends TestCase
   28   {
   29   
   30       /**
   31        * Root package containing tests.
   32        */
   33       private static final String PACKAGE_ROOT = "org.displaytag";
   34   
   35       /**
   36        * logger.
   37        */
   38       private static Log log = LogFactory.getLog(TestAll.class);
   39   
   40       /**
   41        * Basic constructor - called by the test runners.
   42        * @param name test name
   43        */
   44       public TestAll(String name)
   45       {
   46           super(name);
   47       }
   48   
   49       /**
   50        * Iterates over the classes accessible via the iterator and adds them to the test suite.
   51        * @param suite TestSuite empty test suite
   52        * @param classIterator iterator on loaded classes
   53        * @return int number of testcases added to suite
   54        */
   55       private static int addAllTests(TestSuite suite, Iterator classIterator)
   56       {
   57           int testClassCount = 0;
   58           while (classIterator.hasNext())
   59           {
   60               Class testCaseClass = (Class) classIterator.next();
   61   
   62               try
   63               {
   64                   Method suiteMethod = testCaseClass.getMethod("suite", new Class[0]);
   65                   Test test = (Test) suiteMethod.invoke(null, new Class[0]); // static method
   66                   suite.addTest(test);
   67               }
   68               catch (NoSuchMethodException e)
   69               {
   70                   suite.addTest(new TestSuite(testCaseClass));
   71               }
   72               catch (Exception e)
   73               {
   74                   log.error("Failed to execute suite ()", e);
   75               }
   76               if (log.isDebugEnabled())
   77               {
   78                   log.debug("Loaded test case: " + testCaseClass.getName());
   79               }
   80               testClassCount++;
   81           }
   82           return testClassCount;
   83       }
   84   
   85       /**
   86        * Dynamically create a test suite from a set of class files in a directory tree.
   87        * @throws Throwable in running the suite() method
   88        * @return TestSuite for all the found tests
   89        */
   90       public static Test suite() throws Throwable
   91       {
   92           try
   93           {
   94               String className = TestAll.class.getName();
   95               URL testFile = TestAll.class.getResource("TestAll.class");
   96               log.debug(testFile.getFile());
   97               File classRoot = new File(URLDecoder.decode(testFile.getFile(), "UTF-8")).getParentFile();
   98               while (className.indexOf(".") > -1)
   99               {
  100                   classRoot = classRoot.getParentFile();
  101                   className = className.substring(className.indexOf(".") + 1, className.length());
  102               }
  103               log.debug("Looking for classes in " + classRoot);
  104   
  105               ClassFinder classFinder = new ClassFinder(classRoot, PACKAGE_ROOT);
  106               TestCaseLoader testCaseLoader = new TestCaseLoader();
  107               testCaseLoader.loadTestCases(classFinder.getClasses());
  108               TestSuite suite = new TestSuite();
  109               int numberOfTests = addAllTests(suite, testCaseLoader.getClasses());
  110               if (log.isDebugEnabled())
  111               {
  112                   log.debug("Number of test classes found: " + numberOfTests);
  113               }
  114               return suite;
  115           }
  116           catch (Throwable t)
  117           {
  118               // This ensures we have extra information.
  119               // Otherwise all we get is a "Could not invoke the suite method." message.
  120               log.error("suite()", t);
  121               throw t;
  122           }
  123       }
  124   }
  125   
  126   
  127   /**
  128    * This class is responsible for searching a directory for class files. It builds a list of fully qualified class names
  129    * from the class files in the directory tree.
  130    * @author Fabrizio Giustina
  131    * @version $Revision: 902 $ ($Author: fgiust $)
  132    */
  133   
  134   class ClassFinder
  135   {
  136   
  137       /**
  138        * List of found classes (names).
  139        */
  140       private List classNameList = new ArrayList();
  141   
  142       /**
  143        * length of the base package String.
  144        */
  145       private int startPackageLength;
  146   
  147       /**
  148        * Construct the class finder and locate all the classes in the directory structured pointed to by
  149        * <code>classPathRoot</code>. Only classes in the package <code>packageRoot</code> are considered.
  150        * @param classPathRoot classpath directory where to search for test cases
  151        * @param packageRoot root package for tests to be included
  152        */
  153       public ClassFinder(File classPathRoot, String packageRoot)
  154       {
  155           startPackageLength = classPathRoot.getAbsolutePath().length() + 1;
  156           String directoryOffset = packageRoot.replace('.', File.separatorChar);
  157           findAndStoreTestClasses(new File(classPathRoot, directoryOffset));
  158       }
  159   
  160       /**
  161        * Given a file name, guess the fully qualified class name.
  162        * @param file class file
  163        * @return class name
  164        */
  165       private String computeClassName(File file)
  166       {
  167           String absPath = file.getAbsolutePath();
  168           String packageBase = absPath.substring(startPackageLength, absPath.length() - 6);
  169           String className;
  170           className = packageBase.replace(File.separatorChar, '.');
  171           return className;
  172       }
  173   
  174       /**
  175        * This method does all the work. It runs down the directory structure looking for java classes.
  176        * @param currentDirectory directory to search class files in
  177        */
  178       private void findAndStoreTestClasses(File currentDirectory)
  179       {
  180           String[] files = currentDirectory.list();
  181           for (int i = 0; i < files.length; i++)
  182           {
  183               File file = new File(currentDirectory, files[i]);
  184               String fileBase = file.getName();
  185               int idx = fileBase.indexOf(".class");
  186               final int CLASS_EXTENSION_LENGTH = 6;
  187   
  188               if (idx != -1 && (fileBase.length() - idx) == CLASS_EXTENSION_LENGTH)
  189               {
  190                   String className = computeClassName(file);
  191                   classNameList.add(className);
  192               }
  193               else
  194               {
  195                   if (file.isDirectory())
  196                   {
  197                       findAndStoreTestClasses(file);
  198                   }
  199               }
  200           }
  201       }
  202   
  203       /**
  204        * Return the found classes.
  205        * @return Iterator on classes names
  206        */
  207       public Iterator getClasses()
  208       {
  209           return classNameList.iterator();
  210       }
  211   }
  212   
  213   
  214   /**
  215    * Responsible for loading classes representing valid test cases.
  216    * @author Fabrizio Giustina
  217    * @version $Revision: 902 $ ($Author: fgiust $)
  218    */
  219   
  220   class TestCaseLoader
  221   {
  222   
  223       /**
  224        * list containing laded classes.
  225        */
  226       private List classList = new ArrayList();
  227   
  228       /**
  229        * Load the classes that represent test cases we are interested.
  230        * @param classNamesIterator An iterator over a collection of fully qualified class names
  231        */
  232       public void loadTestCases(Iterator classNamesIterator)
  233       {
  234           while (classNamesIterator.hasNext())
  235           {
  236               String className = (String) classNamesIterator.next();
  237               try
  238               {
  239                   Class candidateClass = Class.forName(className);
  240                   addClassIfTestCase(candidateClass);
  241               }
  242               catch (ClassNotFoundException e)
  243               {
  244                   System.err.println("Cannot load class: " + className + " " + e.getMessage());
  245               }
  246               catch (NoClassDefFoundError e)
  247               {
  248                   System.err.println("Cannot load class that " + className + " is dependant on");
  249               }
  250           }
  251       }
  252   
  253       /**
  254        * Adds testCaseClass to the list of classes if the class extends TestCase and it's not abstract.
  255        * @param testCaseClass class to test
  256        */
  257       private void addClassIfTestCase(Class testCaseClass)
  258       {
  259           if (TestCase.class.isAssignableFrom(testCaseClass)
  260               && !TestAll.class.isAssignableFrom(testCaseClass)
  261               && !Modifier.isAbstract(testCaseClass.getModifiers()))
  262           {
  263               classList.add(testCaseClass);
  264           }
  265       }
  266   
  267       /**
  268        * Obtain an iterator over the collection of test case classes loaded by <code>loadTestCases</code>.
  269        * @return Iterator on loaded classes list
  270        */
  271       public Iterator getClasses()
  272       {
  273           return classList.iterator();
  274       }
  275   }

Home » displaytag-1.1.1-src » org » displaytag » test » [javadoc | source]