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"));
}
}
}