package com.javaranch.common ; import java.util.* ; import java.io.* ; import java.text.* ; import java.lang.reflect.* ; /** Stand alone program to execute all unitTest() methods in a com tree.

This program will scan a com tree for all class files. Every class file will be loaded. If the class file is not an interface or an anonymous class, the unitTest() method will be invoked. If the unitTest() method is not found, it will be reported.

PREPARING FILES FOR UNIT TESTING

A proper unitTest() method will have the following header:

The TestLog object can be found in com.javaranch.common.

Most tests will look something like this:

e.g.

In this case, if s.length() does not result in 14 a unit test log message will be generated that looks something like this:

This example shows the time, date, source file name (com.javaranch.common.Str), the line of the file (2132), the value actually generated (13) and the value that was expected (14).

You can also specify an additional log message if you like:

Of course, the message will only be shown if the test fails.

Your computation and expected result values must be of the same type. They can be any primitive except boolean. Objects are okay too as long as they properly implement the equals() and toString() methods.

Booleans have their own slightly different methods:

If the computation results in a false, a unit test log message will be generated.

If you are performing a unit test that doesn't simply boil down to a boolean or comparison, you can use these methods:

The first will generate a unit test log message like this:

If you pass "Too many pancakes" to the second method, it will generate a unit test log message like this:

RUNNING THIS PROGRAM

If you activate this program without passing any parameters, it will try to find the com tree in the current directory. If it cannot find the com tree, it will try to find class files in the current directory.

You can pass a parameter that represents the directory where the com tree can be found. If a directory is not found, this program will search for classes in that directory.

A parameter can specify an exact file, in which case only that one file is processed. Wildcards are not accepted.

Here are some examples assuming that the JavaRanch common classes com tree is in the C:\java directory on a windows system. The first part of each example is the Windows console prompt showing the current directory. It is also assumed that the classpath is set to C:\java.

Any of these three examples would test one class file, com.javaranch.common.Str. If you were to create a file called unittest.bat that contained this one line:

and put it somewhere that your Windows PATH environment variable references, you could then use the following commands:

To test all of the classes in the com.javaranch.common package:

To test all of the classes in the com tree (including com.javaranch.common and, say, com.sun.common):

This program will have an exit value of how many failures there were. An exit value of zero means that all unit tests were successful.

Suggested practices:

- - - - - - - - - - - - - - - - -

Copyright (c) 1999-2001 Paul Wheaton

Copyright (c) 1999-2000 EarthWatch, Inc. You are welcome to do whatever you want to with this source file provided that you maintain this comment fragment (between the dashed lines). Modify it, change the package name, change the class name ... personal or business use ... sell it, share it ... add a copyright for the portions you add ...

My goal in giving this away and maintaining the copyright is to hopefully direct developers back to JavaRanch.

I originally developed this class while working as a contractor at EarthWatch, Inc. in Longmont, Colorado. They gave me permission to distribute this code this way provided that their message would also be carried along. Their message is that they hire Java programmers and would like you to consider working with them. I have to say that my experience with them was first rate and I would encourage engineers to work there. Check out their web site at http://www.digitalglobe.com.

The original source can be found at JavaRanch

- - - - - - - - - - - - - - - - -

@author Paul Wheaton */ public class UnitTest { private static TestingLog log ; private static int pass = 0 ; private static int fail = 0 ; private static boolean treeMode = true ; // go through the com tree, or do just this directory private static class TestingLog extends TestLog { private ErrorLog summary ; private String prefix ; private boolean verbose = false ; TestingLog() { summary = new ErrorLog(); summary.setInternalLog( true ); summary.setConsole( false ); SimpleDateFormat f = new SimpleDateFormat("_yyyyMMdd_HHmmss"); String fileName = "UnitTestLog" + f.format( new Date() ) + ".txt" ; try { setLogFile( fileName ); } catch( IOException e ) { String message = "could not open log file " + fileName ; System.out.println( message ); summary.add( message ); } } private String getLineNumber() { String returnVal = "" ; try { throw new Exception(); } catch ( Exception e ) { StringWriter stringWriter = new StringWriter(); e.printStackTrace( new PrintWriter( stringWriter , true ) ); Str s = new Str( stringWriter.toString() ); int pos1 = s.indexOf( ".unitTest(" ); if ( pos1 > 0 ) { int pos2 = s.indexOf( ')' , pos1 ); if ( pos2 > 0 ) { pos1 += 10 ; s = s.get( pos1 , pos2 - pos1 ); returnVal = s.from( s.indexOf( ':' ) ).toString(); } } } return returnVal ; } public void add( String message ) { String s = prefix + getLineNumber() + ')' + message ; super.add( s ); summary.add( s ); } void setClassName( String currentClassName ) { prefix = '(' + currentClassName ; } void startMessage() { if ( verbose ) { super.add( prefix + ")start" ); } } void stopMessage() { if ( verbose ) { super.add( prefix + ")complete" ); } } void anonymousSkipMessage() { if ( verbose ) { super.add( prefix + "anonymous inner class - skipping" ); } } void interfaceSkipMessage() { if ( verbose ) { super.add( prefix + "interface - skipping" ); } } void showSummary() { String[] s = summary.getList(); Str bigString = new Str() ; if ( verbose ) { bigString.append( "\n\nSummary of failures:\n" ); for( int i = 0 ; i < s.length ; i++ ) { bigString.append( "\n " + s[ i ] ); } bigString.append( "\n\n" ); } bigString.append("classes passed: " + pass + " classed failed: " + fail ); super.add( bigString.toString() ); } } private static void test( String className ) { log.setClassName( className ); log.startMessage(); int logCount = log.numErrors(); try { Class c = Class.forName( className ); if ( c.isInterface() ) { log.interfaceSkipMessage(); } else { Method m = c.getDeclaredMethod( "unitTest" , new Class[]{ TestLog.class } ); m.invoke( null , new Object[]{ log } ); } } catch( NoClassDefFoundError e ) { log.add( "class is not in proper package" ); } catch( NoSuchMethodException e ) { log.add( "could not find unitTest() method" ); } catch( Throwable e ) { log.add( "exception encountered during unit test: " + e ); } if ( log.numErrors() > logCount ) { fail++ ; } else { pass++ ; } log.stopMessage(); } private static void processDirectory( File dir , String packageName ) { System.out.println( "processing package " + packageName ); String[] files = dir.list(); for( int i = 0 ; i < files.length ; i++ ) { String name = files[ i ]; String fullPackageName = packageName + "." + name ; File f = new File( dir , name ); if ( f.isDirectory() ) { if ( treeMode ) { processDirectory( f , fullPackageName ); } } else if ( name.endsWith( ".class" ) ) { Str s = new Str( fullPackageName ); s.trimTrailTo( '.' ); boolean anon = false ; int trailingDigits = s.trailingDigits(); if ( trailingDigits > 0 ) { if ( s.charAt( s.length() - ( trailingDigits + 1 ) ) == '$' ) { anon = true ; } } String className = s.toString(); if ( anon ) { log.setClassName( className ); log.anonymousSkipMessage(); } else { test( className ); } } } } private static String getPackage( File f ) { Str s = new Str( f.getAbsolutePath() ); s.replace( '/' , '.' ); s.replace( '\\' , '.' ); while( s.endsWith( "." ) ) { s.setLength( s.length() - 1 ); } int dotCom = s.indexOf( ".com." ); return s.after( dotCom ).toString(); } public static void main( String[] args ) throws Exception { log = new TestingLog(); boolean didTesting = false ; String path = "."; if ( args.length == 1 ) { path = args[0]; } File comDir = new File( path + "/com" ); if ( comDir.exists() ) { if ( comDir.isDirectory() ) { processDirectory( comDir , "com" ); didTesting = true ; } else { System.out.println( "'com' is not a directory" ); } } else { File f = new File( path ); if ( ! f.exists() ) { f = new File( path + ".class" ); } if ( f.exists() ) { String packageName = getPackage( f ); if ( f.isDirectory() ) { treeMode = false ; processDirectory( f , packageName ); didTesting = true ; } else { Str s = new Str( packageName ); s.trimTrailTo( '.' ); test( s.toString() ); didTesting = true ; } } else { System.out.println( "could not determine file or directory." ); } } if ( didTesting ) { log.showSummary(); System.exit( fail ); // we may have loaded some stuff that kicked off a thread or two. } } /** Used for testing this class, do not call directly.

*/ public static void unitTest( TestLog log ) { // xxx need tests } }