[an error occurred while processing this directive]

Java Test Software


Writing a Tester Subclass

Java test software can be constructed by writing a subclass of class Tester. This class is a base class for line-oriented, command-driven, interactive and batch testing. The Tester class understands the following single-character commands:
? [ command_abbreviation ... ]
if there are arguments, display full descriptions for commands matching arguments; otherwise, display menu of commands

#
line is a comment

!
terminate the program

@ [ fileName ]
with fileName argument, insert lines from the named file; otherwise insert lines from the terminal

.
end the current insert

+
turn echoing on

-
turn echoing off

Empty lines and lines that begin with a white character are ignored by the command interpreter. Echo control is only effective while reading from a batch file.

A Tester subclass contains definitions for three methods: a constructor, an addCommands() method, and a main() method. The constructor and main() methods should be the same as the ones defined in the Tester class except that the name Tester should be replaced by the name of the Tester subclass. The following are the constructor and main() methods from the FormattingTester class, which is designed for testing the Formatting class.

    /** FormattingTester() returns a new Tester.
     */
    public FormattingTester()
    throws FileNotFoundException, IOException {
	super();
    }  // public FormattingTester()

    /** If this program is executed with no command line argument then it
     *  executes commands entered from the terminal.  If this program is
     *  executed with a single command-line argument then that argument
     *  is interpreted as a file name.  The program attempts to open the
     *  named file and execute the commands in it.  If the open fails, or
     *  if there is more than one command-line argument, then the program
     *  terminates with an error message.
     */
    public static void main(String[] args)
    throws FileNotFoundException, IOException {
	Tester tester = new FormattingTester();
	tester.openStream(args);
	tester.addCommands();
	tester.doCommands();
    }  // public static main(String[])

Subclasses can add new commands by redefining the addCommands() method. This method should have the following form.

    /** addCommands() adds testing commands to the command table.
     */
    public void addCommands() {
	super.addCommands();
	new_command_definition
	    .
	    .
	    .
	new_command_definition
    }  // public void addCommands()
The line
    super.addCommands();
ensures that the basic commands are recognized.

For each new command, code like the following is added. This example is from the FormattingTester class.

    commandTable.add(new Command() {
	{
	    name = new String("flc");
	    arguments = new String("str w fc");
	    brief = new String("displays a string filled left with " +
		    "characters");
	    full = new String("displays str in a field of width w " +
		    "filled left with copies of fc");
	}
	public void execute(LineScanner ls) {
	    String str = ls.readString();
	    int w = ls.readInt();
	    char fc = ls.readChar();
	    ls.readEnd();
	    if (ls.errorCount() == 0) {
		System.out.println("|" +
			Formatting.filledLeft(str, w, fc) + "|");
	    }
	}
    });

This code creates and defines a new instance of class Command and adds it to commandTable (class CommandTable), which is a table containing all of the commands for a Tester. The Command defined in this example is given the name "flc" by the name String. It has three arguments named "str", "w", and "fc", as defined in the arguments String. The brief and full Strings determine messages that are printed in response to the ? (help) command.

The declaration for the execute() method determines what the command will do when it is executed. The execute method has a LineScanner parameter, which has methods for breaking a line up into tokens and interpreting the tokens. The first token, the command name, has already been read and passed to commandTable, which looked it up and called the execute() method defined for it. Thus the code that you write in this method assumes that the LineScanner is ready to read its first argument.

The first three lines in this exceute() method are reading the command arguments "str" (type String), ""w" (type int), and "fc" (type char). If errors arise in reading these arguments then error messages are recorded in the LineScanner. The line is checked for extraneous arguments by calling readEnd(). This method also prints out any error messages that have been recorded in the LineScanner.

After the command arguments have been gathered, the execute() method does its work by calling the filledLeft() method of the Formatting class.

Often, a Tester subclass defines a command for each public method in the class under test, though sometimes it makes sense to define commands that call several methods. A Tester subclass can define new instance variables for holding objects that are being tested. For example, if a CircularList class defines a method that appends one CircularList onto another then it is useful to add a Hashtable instance variable that can store and retrieve CircularLists by name. Then the execute() method for testing the append method should have two String arguments - the names of the two CircularLists that are to be appended.

Using a Tester Subclass

A Tester subclass can be executed by giving the command
java class_name
where class_name is the name of the Tester subclass. If you have written a file containing batch testing commands then you can give the command
java class_name command_file_name
where class_name is the name of the Tester subclass and command_file_name is the name of the file containing the testing commands.

When the main() method of a Tester subclass is run, the CommandTable accepts abbreviations of command names as long as the abbreviation is a prefix of the command name and is not a prefix of any other command name. Thus a command named "append" can be abbreviated as "a" as long as there are no other commands that begin with "a". There must be white space between the command name and the first argument, and between each pair of arguments. If you need a String argument with white space in it then you can enclose the argument in matching single or double quotes. Inside quotes, you can use simple escape sequences, such as "\t" for a tab or "\n" for a newline.

Obtaining and Installing the Tester Software

The tester software is available in the file ~gshute/public/softeng/test-Java.jar. If you already have done some Java programming and have a classes directory which is in your class path, then all you need to do is copy this file to the directory that contains your classes directory and give the following command.
jar xf test-Java.jar
This will create a subdirectory classes/ioutil, where the various test software classes are located.

If you do not have a classes directory then you can put the test.jar file wherever you will be doing Java work and give the jar command shown above. This will create the classes directory with the ioutil subdirectory. However, you will need to set a UNIX CLASS_PATH variable so that the Java compiler can locate the tester software. You can do this by adding the following lines at the end of the .personal file in your home directory.

    set path = (/usr/local/java1.2/bin $path)
    setenv CLASSPATH "$HOME/path_to_classes:."
The first line is only needed if you need Java 1.2 classes. If you are using version 1.2 then you will need to log onto a CS department machine. In the last line, path_to_classes is the path from your login directory to your classes directory, including the name classes at the end. If you do not have a .personal file then you should create one with the text shown above.

The .personal file is only read immediately after logging on, so it will not take effect until the next time you log on. You can have the UNIX command interpreter reread this file by giving the following command.

source .personal

Examples

The following links lead to client documentation for two classes and the two Tester subclasses designed for testing them.

Complete code for the CircularList and Formatting classes can be found in the classes/ioutil subdirectory, which also contains a suite of batch test input files for the Formatting class. These files are named FormattingTester.in and FormattingTester.in1 through FormattingTester.in8. The first file just displays a menu of testing commands and then transfers control to the other 8 files, each of which contains commands for testing one or two of the Formatting class methods. The file FormattingTester.out contains the output generated by giving the following command.

java FormattingTester FormattingTester.in

[an error occurred while processing this directive]