How to Find and Execute All JUnit Tests in a Directory Hierarchy
This note is for users of the Ant build tool. I’ve modified an AllTests class to automatically add Test classes to a TestSuite by recursively checking a directory hierarchy for classes with “test” or “Test” in their names.
The customization needed to incorporate these classes into your own system is minimal. Look for “CUSTOMIZE_THIS” comments.
- change the package names
- change the hard-coded directory and class hierarchy reference.
First is the AllTests.java file:
/* CUSTOMIZE_HERE */ package com.cordiem.tests; import java.util.Enumeration; import java.util.Vector; import junit.framework.*; import junit.runner.BaseTestRunner; /* CUSTOMIZE_HERE */ import com.cordiem.examples.FindTestClasses; /** * TestSuite that runs all the sample tests. Customize this * class to your environment by looking for CUSTOMIZE_HERE * comments. * * @author David Medinets */ public class AllTests { public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static Test suite() { Vector v = null; try { FindTestClasses ftc = new FindTestClasses(); /* CUSTOMIZE_HERE */ ftc.setRootDir("com\\cordiem\\tests"); ftc.findFiles(); v = ftc.results(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } TestSuite suite = new TestSuite("Framework Tests"); for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { Class c = (Class)e.nextElement(); /* CUSTOMIZE_HERE */ if (! c.getName().equals("com.cordiem.tests.AllTests")) { suite.addTestSuite(c); System.out.println("Adding " + c.getName() + " to the Test suite."); } } return suite; } }
Second is the FindTestClasses.java file:
/* CUSTOMIZE_HERE */ package com.cordiem.examples; import java.io.*; import java.util.Vector; import java.lang.reflect.*; /** Finds classes with "Test" in their names. * * @author David Medinets **/ public class FindTestClasses { /** the directory to start looking in */ String rootDir = null; /** a place to store the file names. */ Vector classList = new Vector(); // TODO: create an excluded directory list. /** a do-nothing no-parameter constructor. */ public FindTestClasses() { } public void setRootDir( String inpRootDir ) { rootDir = inpRootDir; } public void findFiles() throws Exception { build_stack(rootDir); } public Vector results() { return(classList); } /** The workhorse of this class. It does the job of reading directories and * recursing down the directory tree. **/ private void build_stack(String p_directory_name) throws Exception { if (null == p_directory_name || 0 == p_directory_name.length()) { return; } // TODO: If the directory being examined should be ignored, then leave this method. String[] sFiles = null; File dir = new File(p_directory_name); if (false == dir.canRead()) { return; // silently ignore unreadable directories. } sFiles = dir.list( new FilterJava() ); if (null == sFiles) { return; } String filePath = null; for (int i = 0; i < sFiles.length; i++) { int testIndex = sFiles[i].indexOf("test"); if (-1 == testIndex) { testIndex = sFiles[i].indexOf("Test"); } if (-1 != testIndex) { filePath = dir.toString() + (String)System.getProperty("file.separator") + sFiles[i]; // change slashes to periods and remove the .java from the // end of the path to create the class name. StringBuffer className = new StringBuffer(replace(filePath, '\\', '.')); className.setLength( className.length() - 5); try { Class c = Class.forName(className.toString()); classList.add(c); } catch (ClassNotFoundException e) { throw new Exception("Problem loading class [" + className.toString() + "]."); } } } // Get list of subdirectories for recursion. String[] sDirs = dir.list(new FilterDirectoryOnly()); for (int i = 0; i < sDirs.length; i++) { build_stack(p_directory_name + (String)System.getProperty("file.separator") + sDirs[i]); } } private String replace(String str, char oldChar, char newChar) { char curChar; StringBuffer sbStr = new StringBuffer(str); StringBuffer sbRv = new StringBuffer(); for (int i=0; i < sbStr.length(); i++) { curChar = sbStr.charAt(i); if (curChar == oldChar) { sbRv.append(newChar); } else { sbRv.append(curChar); } } return(sbRv.toString()); } /** implements FilenameFilter to find directories * * @author David Medinets */ private class FilterDirectoryOnly extends Object implements FilenameFilter { /** a do-nothing no-parameter constructor. */ public FilterDirectoryOnly() { } /** accepts directories. */ public boolean accept(File dir, String name) { File temp = new File(dir + (String)System.getProperty("file.separator") + name); return(temp.isDirectory()); } } /** implements FilenameFilter to find .java files. * * @author David Medinets */ private class FilterJava extends Object implements FilenameFilter { /** a do-nothing no-parameter constructor. */ public FilterJava() { } /** accepts .java files. */ public boolean accept(File dir, String name) { return(name.endsWith(".java")); } } }