Skip to main content

The World's Simplest Unit Testing Framework

Posted by cayhorstmann on October 24, 2006 at 6:48 PM PDT

??? style="float: right; padding-left: 0.5em;" />I teach computer science at
San Jose State University. In my experience, the habits from the first
programming course stay with students for a long time and are very
difficult to break. (I am always amazed how many seniors in my software
engineering course still use Notepad to edit their Java files.) I want to
get the freshmen to embrace test-driven development right from the
get-go.

??? style="float: left; padding-right: 0.5em;" /> href="http://junit.org">JUnit 4 is href="http://www.instrumentalservices.com/index.php?option=com_content&task=view&id=45&Itemid=52">nice
and simple. Just add @Test, and use assert, which is
a standard Java feature. But unfortunately, that's still too hard for
beginners. Did you every try to get a bunch of freshmen to add a JAR to
their class path? It's not a pretty sight.

So, this is what I ended up doing. I require that every program prints
out the value that the student expects:

public class BankAccountTester
{
   public static void main(String[] args)
   {
      BankAccount momsSavings = new BankAccount(1000);
      momsSavings.deposit(100);
      double balance = momsSavings.getBalance();
      System.out.println("Balance: " + balance);
      System.out.println("Expected: 1100");
   }
}

The printout is

Balance: 1100
Expected: 1100

That's the “green bar” moment in the world's simplest
unit test framework
.

I wrote an Ant extension that automatically checks the output and deals
with silly issues such as roundoff:

Balance: 1034.2999999997
Expected: 1034.30

The students don't run Ant; that's just for my grading automation. My
grading script contains an entry

    <java classpath="${submit.dir}"
          classname="${mainclass}"
          failonerror="true"
          outputproperty="mainclass.out"
          fork="true" />
    <echo message="${mainclass.out}" />
    <condition property="tester.fail" value="Output not as expected">
      <not>
        <asexpected value="${mainclass.out}" tolerance="${test.tolerance}" />
      </not>
    </condition>

There you have it. TWSUTF is System.out.println("Expected:
...")
and an Ant condition that checks the output.

??? style="float: right; padding-left: 0.5em;" />Big deal, right? Well, it
turns out to be a bigger deal than I thought. The next assignment asks
students to write a class IceCreamCone. And I cruelly ask them to
write the test first.

public class IceCreamConeTester
{
   public static void main(String[] args)
   {
      double height = 6;
      double diameter = 1;
      IceCreamCone waffleCone = new IceCreamCone(height, diameter);
      double volume = waffleCone.getVolume();
      System.out.println("Volume: " + volume);
      System.out.println("Expected: How the !@#$ am I supposed to know?");
   }
}

Now I have them where I want them. They have to figure out the answer
by hand for at least one case. That's very different from running the
program and saying “ok, looks about right”.

Of course, after a few weeks, the simple tests get tedious. We want
multiple tests without writing lots of static methods— href="http://jtf.acm.org/rationale/problem-taxonomy.html#L1">another
no-no in the intro course. And we want the other tests to keep on
trucking when one of them throws an exception. That's the time to break
out JUnit. Now it solves a problem that the students have.

What do you think? Should students get immersed in TDD in their first
Java course, or would it be a better use of time to learn another sorting
algorithm, or some GUI programming, or whatever?