Skip to main content

Extreme Teaching: Introducing Objects

August 28, 2003


Often, the people who spend their days doing object-oriented
programming don't communicate with those who spend their days
teaching object-oriented programming. It means that
innovations on each side of this divide are often not shared with the
other. Recently, the FIT framework has been gaining popularity as
an acceptance-testing framework. FitNesse is a wiki-based wrapper for
FIT that adds more functionality.

Together, these applications allow a teacher to write an executable
assignment. In other words, the teacher can specify what the
assignment is to do, in such a way that the student, faculty member, or
grader can run this spec against the students' efforts throughout the
development phase. This means that the spec itself can also help the
student make progress by informing the student of what needs to be
done next. A student can work through an assignment knowing which
parts have been satisfied at any moment.

This article introduces a basic example of how you might use
acceptance testing to lead students through an assignment. We'll begin
with a rant against "Hello World," continue with a quick
introduction to FitNesse, and conclude with the tables and fixture for
running this example.

A First Object-Oriented Program

The "Hello World" program is traditionally the first
code that a CS 1 student compiles and runs. The program looks
something like this.

public class HelloWorld {
  public static void main(String [] args){
    System.out.println("Hello, world.");

The student saves this as, compiles the source
code into a class file, HelloWorld.class, and runs HelloWorld. After
all of this typing, the student is rewarded by seeing "Hello,
world." in the console window.

I've written elsewhere
about the problems with starting a course on object-oriented
programming with this non-object-oriented program. There are no
objects anywhere. Almost everything happens inside of the
main() method. How do you treat this initially confusing
main() method? Do you explain the components of its
signature first, or do you tell the students to just type it in and
say you'll explain it later? The first option requires you to explain
static methods in a class that contains no other methods, a return
type for a method that doesn't return anything, access levels for a
method that doesn't restrict access in any way, method parameters in a
method that never uses the args variable, and arrays of
String objects that are never set.

In the talkback to my original ONJava article, one reader pointed
out that "Hello World" was the smallest possible program
that a student can write and have working code that provides feedback
to the user. In a way, it is a verification that their development
environment is set up right and that they know how to save code to the
right spot and then compile and run it.

In the followup
, I proposed the following first assignment for
students. They have to have to write and compile the code that makes
the following two lines work.

Friend friend = new Friend();
String yourName = friend.getName();
// somehow I will display yourName once I have it

Already we can have a rich discussion. The rest of the article
used a custom class loader to lead the student through the process of:

  • Creating a file named and saving it in the
    appropriate directory.
  • Stubbing out the class skeleton: public class Friend{}.
  • Compiling the file into
  • Adding the getName() method that returns a String.

The result is a version of that looks something like

public class Friend { 
   public String getName(){
     return "Daniel";

The students have still written a very short piece of code and had
to learn how to save code, compile, and run it. They have also learned
more. They weren't given the code they had to write -- they had to
figure it out from the clues in the client code. The client code
specifies that it will need a class named Friend with a
method named getName(), with certain expected

Getting FitNesse Up and Running

The obstacle to using the approach detailed in the second article
was that it required quite a bit of coding to make the custom class
loader provide the appropriate feedback to lead a new user through the
project. The FIT framework was
designed by Ward Cunningham to allow customers to use simple HTML
tables to specify the expected behavior of an application. The
customer would write the tables, the developer would write the code,
and the developers would also write a little bit of glue code to tie
the two together. Much of Ward's work has been captured by others in
the practices and principles of Extreme Programming(XP). Although I do
advocate using Test-Driven Design and other aspects of XP in the
classroom, FIT and the techniques described in this article can be
used whether or not you intend to do so.

The remainder of this article will show how you can use the FIT
framework in the classroom to specify and monitor an assignment. In an
intro course, the instructor can specify the requirements in tables and
the students can write the code that makes the tests pass. Initially,
the instructors will need to write the glue code. These so-called
acceptance tests are not the same as unit tests and are meant
to supplement the unit testing that a student does. Unit tests, however,
are outside of the scope of this article.

Bob and Micah Martin have open-sourced FitNesse, a wiki-based front end
for FIT that is written in Java. In this article, you use FitNesse as
an engine for driving the student assignment. Download the latest
version of FitNesse and unzip it. The fitnesse directory
contains two run files: run.bat for Windows and for Unix. You
can also run using fitnesse.jar from the command line as follows:

java -cp fitnesse.jar: fitnesse.Fitnesse -p 8099

Here I've used the extra flag -p 8099 to use port
8099 instead of the default port 80. If you are already using port 80
to serve web pages, you will want to select a different port. Other
command line arguments, documented in the User Guide, let you
specify the location of the top-level pages for the site being served
and whether or not logging is turned on. Open a browser and enter the


If you used the default port, you do not need to include the port
information. If you chose another port, modify the URL
accordingly. The instructions in this tutorial will assume the port is
8099. You should be redirected to http://localhost:8099/FrontPage and be greeted by
"Welcome to FitNesse". Follow the link to FitNesse.UserGuide. If you
are not familiar with wikis, you can find instructions here. You can
also find reference material for writing and running acceptance
tests. Click on the link to RunningAcceptanceTests.

Note: Before going further, please check to see if you are
running the July 28 release of FitNesse. You can determine this by
looking at the .zip file, which is named If your file is,
you will need to take the following steps to clean up your FitNesse
installation. Go to the URL http://localhost:8099/ClassPath. You should see this:

The first and third lines need to be removed. Click on the "Edit"
link in the left column. You'll be taken to an editor that shows this
raw text used to generate the wiki page.

!path c:\javalib\XPWDC Example 
!path fitnesse/classes
!path c:\fit\Release\fit.jar

Comment out the first and third lines by putting # at
the beginning of each line. You should now have this:

#!path c:\javalib\XPWDC Example 
!path fitnesse/classes
#!path c:\fit\Release\fit.jar

Press the Save button and you should be taken back to the
ClassPath page with the first and third classpath lines now gone.

Go to http://localhost:8099/FitNesse.RunningAcceptanceTests. At the
top of the left column you should see the link "Test". Click on it, and after a moment the top of the table
should turn yellow and you should see something like Figure 1.

Figure 1. ClassNotFound when running acceptance test

You need to add eg.Division to the classpath. If you look around
the FitNesse distribution, you will find eg inside of FitNesseRoot/files/examples. Click on the "Edit" link at the top left. Add the line !path FitNesseRoot/files/examples/ below the table, as is highlighted below.

Acceptance tests are run by hitting the '''Test''' button (or
typing ''ALT-t'').  This button appears on any page that has the
'''Test''' attribute set.  See [[Page

Hitting the '''Test''' button is equivalent to using the
following command:{{{!r fitnesse.FitFilter}}}(See

Any tables that are on the page are run through the Fit framework
(See ).

So, for example, click the '''Test''' button (or type ''ALT-t'')
and see what happens to the table below:


!path FitNesseRoot/files/examples/


You may also run FitNesseTests by using the CommandLineTestRunner!

Compare this text to the generated page and you will see that cells
in the table are separated by "|", that classpaths are indicated by
the keyword !path, and that links can be created by so-called
wiki words. You can get the details on these and other wiki syntax in
the UserGuide.

Save the edited page by pressing the Save button, and then re-run
the tests using the "Test" link. This time the tests should
run. The ones where the output is as expected are colored green. The
ones where the output doesn't match the expected value are colored red
and the expected and actual values are reported, as shown in Figure 2.

Figure 2. Running acceptance tests

This type of table corresponds to what is called the Column
. The columns headed numerator and
denominator correspond to instance variables whose values
are set to the values in the cell. The column headed
quotient() maps to a method call whose expected return
value is contained in the cell. The class containing these variables
and this method is the Division class in the package

Creating Your Harness

In our example, we will use the Action Fixture. With the Action
Fixture, you use the keyword start to load the class that will
contain the methods being called in the remainder of the table. To set
a value using the Action Fixture, you use the keyword enter
followed by a name-value pair. To initiate an action you use the
keyword press followed by the name of the action being
initiated. Finally, to examine a particular value, you use the
check keyword followed by the name of what you are checking and
its expected value.

Let's begin by creating a new page with a table that will lead the
student through the assignment. Edit the RunningAcceptanceTests page
and add the line FriendAssignment to the very end. Save
this page. Now you should see a "?" after the text you just added.

Click on the question mark, and the page FriendAssignment will be
created and you will be taken to the editing page. Here is a
simplistic version of a page that leads the students through this
assignment. The point is to demonstrate how easily you can use FIT and
FitNesse to specify what you want the student's application to do.

Inside of the directory !-FitNesseRoot/files/examples-! 
create a new text file named '''''' and save it inside
of the fitnesse directory.

|!- fit.ActionFixture -!|
| start | !-HelloWorldSetUp-! |
| check | friendDotJava | exists |

Next, add the text to that allows you to compile it
into the class file '''Friend.class''' and compile it.

|!- fit.ActionFixture -!|
| check | friendDotClass | exists |

Finally, add a method to named getName() that returns
a String containing the name ''Gertrude''.

|!- fit.ActionFixture -!|
|check | name | Gertrude |

!path .

Adding the "!-" and "-!" around elements makes sure that the wiki
words won't be interpreted as links. Press Save and you should see
a page like Figure 3.

Figure 3. FriendAssignment in FitNesse

Notice that Test does not appear in the left
column. Click on Properties, check the
Test checkbox and then Save. Next, look at the three
tables. Each uses the ActionFixture class to process the tables. The
first loads the class HelloWorld. This class contains the
glue methods that call into the code your student is writing. The
method friendDotJava() is called, and it returns the
String "exists" if the file exists. Otherwise, it returns
some error message that you can customize.

In the second table, you need to again specify that this table
uses the ActionFixture class, but you don't need to reintroduce
HelloWorld. The friendDotClass() method checks on the
existence of the file Friend.class. Finally, the third table calls the
method name(), which turns around and creates an instance
of Friend and calls the getName() method in Friend. It
checks the String that is returned to see if it is "Gertrude".

The fixture is a Java class that you write named
HelloWorld. Here is the code for, which
you save in the fitnesse directory.

import fit.Fixture;

public class HelloWorld extends Fixture {

  private File source = new File("");
  private File classFile = new File("Friend.class");

  public String friendDotJava(){
    if (source.exists()) return "exists";
    else return " is not in the correct location.";
  public String friendDotClass(){
    if (classFile.exists()) return "exists";
    else return "Friend.class has not been created yet.";
  public String name() {
    Friend friend = new Friend();
    return friend.getName();

In order to compile HelloWorld, you'll need to create,
which you can later delete. Add fit.jar to your classpath and compile Now you can delete and Friend.class.

A student using your harness presses Test. They are
given feedback that indicates that doesn't exist or is not in
the correct location. Once they meet that condition, they run
Test again and work on creating Friend.class by adding
public class Friend{} to and compiling
it. Finally, once Friend.class exists, the middle table will pass and
the bottom table will be colored yellow with a warning that you have a
NoSuchMethodError, as Friend.getName() does
not exist. Once the student creates the getName() method
that returns the String "Gertrude", all of the tests will pass.


The intent of this article was to give you a feel for how you can
lay out an assignment using FIT and FitNesse. Some assignments will
require more than one wiki page for running tests, more than one
fixture for supporting tests, or different types of fixtures. Students
don't need to guess at what you want in an assignment. They can see
the tests and they should have access to the corresponding
Fixtures. This provides examples to them of working code that will be
used to exercise their code.

Daniel H. Steinberg runs and is former editor-in-chief of
Related Topics >> Education   |   Extreme Programming   |