Examples (aka Test Cases)

Pretend for a moment that the method is already defined. Write down two or more expressions that use this method (in correct Java syntax, so that if it were already defined, you could type them in and get answers), along with the "right answer" you expect each example to produce. This step is useful in at least three ways.

  1. It allows you to try out the syntax people will use to invoke the method, and perhaps learn that your first guess at the syntax is inconvenient to use, so you should change the syntax before wasting a lot of time implementing it.
  2. It allows you to discover, early on, that your contract wasn't quite right, and that you actually want different kinds of information going in or out. If that happens, change the contract now and re-write your examples accordingly; that will waste less time than going on and having to change the contract later.
  3. It gives you a ready source of test cases, already in legal Java syntax, thus removing one possible excuse for skipping the Testing step, later.

Start with the simplest possible examples, then work up to more and more complicated examples. In the past, we've been doing this by writing examples in comments in front of the method. As of Feb. 11, we'll use either the JUnit library or the tester library to automate things. In both cases, if we're trying to test methods in a particular class (say, Blah), we'll write a separate class (say, BlahTest) to contain all the test cases for it.

Writing test cases with JUnit

Part of this is very easy: right-click on the Blah class for which you want to write tests, and choose "Create Test Class". You should get a new class named TestBlah, in green, linked to the original class. In this class, you'll probably want to define some instance variables, and also write some methods whose names start with "test", e.g.

public class BlahTest extends junit.framework.TestCase
{
	Blah blah1 = new Blah(whatever, whatever);
	Blah blah2 = new Blah(something else);
	
	/**
	 * testMethod1 : make sure method1 of the Blah class works.
	 * No parameters, no return value; either it succeeds or it fails.
	 */
	public void testMethod1 ()
	{
		this.assertEquals(17, blah1.method1());
		// where 17 is the "right answer" to blah1.method1()
		this.assertEquals(-4, blah2.method1());
		// and -4 is the "right answer" to blah1.method1()
	}

	/**
	 * testMethod2 : make sure method2 of the Blah class works.
	 * No parameters, no return value; either it succeeds or it fails.
	 */
	public void testMethod2 ()
	{
		this.assertEquals(3.8, blah1.method2(), 0.01);
		// tests that the answer to blah1.method2() is within
		// 0.01 of 3.8, i.e. between 3.79 and 3.81.
	}
}
You can write as many of these "test" methods as you want to.

JUnit is very good at testing methods that return int, double, String, or boolean, but not so good at methods that return other classes like Posn, Professor, etc. For those sorts of methods, you're better off using Tester:

Writing test cases with Tester

Since BlueJ doesn't know about the Tester library, it doesn't have a menu selection to create a Tester test class, but it's not hard. Suppose you've got a class Blah for which you want to write test cases. In BlueJ, choose "New Class..." and choose a name like BlahTest. (There's nothing magical about this name, although certain things will work better if it contains the letters "Test".) Add an import tester.*; statement at the top, and add a static testEverything method for convenience (see below). As in JUnit, you can define a bunch of instance variables for instance of the Blah class that you want to use for test cases. And as in JUnit, you'll typically write a bunch of methods whose names start with "test". They look a little different from the ones in JUnit, but they serve the same purpose.

import tester.*;

public class BlahTest
{
	Blah blah1 = new Blah(whatever, whatever);
	Blah blah2 = new Blah(something else);
	
	/**
	 * testEverything: run all the test cases in the class.
	 * No parameters, no return values, but produces a report in the terminal
	 * window.
	 */
	public static void testEverything()
	{
		Tester.run (new PosnExamples());
	}
	
	/**
	 * testMethod1 : make sure method1 in the Blah class works.
	 *
	 * @param  t  the Tester to use
	 * No return value; it either succeeds or fails.
	 */
	public void testMethod1 (Tester t)
	{
		t.checkExpect (blah1.method1(), 17);
		t.checkExpect (blah2.method1(), -4);
		// again assuming that the "right answers" to
		// blah1.method1() and blah2.method1() are
		// 17 and -4 respectively.
	}

	/**
	 * testMethod2 : make sure method2 in the Blah class works.
	 *
	 * @param  t  the Tester to use
	 * No return value; it either succeeds or fails.
	 */
	public void testMethod2 (Tester t)
	{
		t.setTolerance (0.01);
		// from now on all double comparisons will be "within 0.01"
		// until we setTolerance to something else
		t.checkExpect (blah1.method2(), 3.8);
		// tests whether actual answer is between 3.79 and 3.81
	}
}

Last modified: Wed Feb 11 09:44:30 EST 2009
Stephen Bloch / sbloch@adelphi.edu