Stopping to use a debugger is time-consuming. Better to test beforehand. The methodology of unit testing has been around for a long time, but has been overshadowed by newer methodologies. Unit testing is a tried and true means of getting your code tested in small pieces. Typically, in an OO language like Java, unit testing is applied to individual classes, in contrast to “black box” testing where the entire application is tested.
I have long been an advocate of this very basic testing methodology. Indeed, developers of the software methodology known as Extreme Programming (XP for short; see http://www.extremeprogramming.org) advocate writing the unit tests before you write the code, and also advocate running your tests almost every time you compile. This group of extremists has some very well-known leaders, including Gamma and Beck of Design Patterns fame. While I am not yet ready to unconditionally endorse all aspects of Extreme Programming, I certainly go along with their advocacy of unit testing.
Indeed, many of my classes come with a “built-in” unit
test. Classes that are not main programs in their own right often
include a main
method that just
tests out the functionality of the class. Here is an
example:
/** A simple class used to demonstrate unit testing. */ public class Person { protected String fullName; protected String firstName, lastName; /** Construct a Person using his/her first+last names. */ public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } /** Get the person's full name */ public String getFullName( ) { if (fullName != null) return fullName; return firstName + " " + lastName; } /** Simple test program. */ public static void main(String[] argv) { Person p = new Person("Ian", "Darwin"); String f = p.getFullName( ); if (!f.equals("Ian Darwin")) throw new IllegalStateException("Name concatenation broken"); System.out.println("Fullname " + f + " looks good"); } }
What surprised me is that, before encountering XP, I used to think I did this often, but an actual inspection of two projects indicated that only about a third of my classes had test cases, either inside or externally. Clearly what is needed is a uniform methodology. That is provided by JUnit.
JUnit is a Java-centric methodology for
providing test cases. You can freely download JUnit from the obvious
web site, http://www.junit.org.
JUnit is a very simple but useful testing tool. It is easy to use;
you just write a test class that has a series of methods whose names
begin with test
. JUnit uses
introspection (see Chapter 25) to find all these methods, and runs them for
you! There are extensions to JUnit for purposes as diverse as load
testing and testing Enterprise JavaBeans (EJB); there are links to
these on the JUnit web site.
How do you get started using JUnit? All that’s necessary is to
write a test. Here I have excerpted the test from my
Person
class and placed it into a class
PersonTest
. Note the obvious
naming pattern.
import junit.framework.*; /** A simple test case for Person */ public class PersonTest extends TestCase { /** JUnit test classes require this constructor */ public PersonTest(String name) { super(name); } public void testNameConcat( ) { Person p = new Person("Ian", "Darwin"); String f = p.getFullName( ); assertEquals(f, "Ian Darwin"); } }
To run it, I need only compile the test and invoke the test harness
junit
:
daroad.darwinsys.com$ jikes PersonTest.java daroad.darwinsys.com$ java junit.textui.TestRunner PersonTest . Time: 0.188 OK (1 tests) daroad.darwinsys.com$
The use of a full class name is a bit tedious, so I have a script named jtest that invokes this; I just say jtest Person and it runs the previous command for me.
#!/bin/sh exec java junit.textui.TestRunner ${1}Test
If you prefer flashier GUI output, there are several JUnit variants (built using Swing and AWT; see Chapter 13) that will run the tests with a GUI.
JUnit offers classes for building comprehensive test suites and comes with considerable documentation of its own; download the program from the web site listed earlier.
Also, for testing graphical components, I have developed a simple component tester; it is described in Section 12.3.
Remember: Test early, test often!
3.135.200.14