Test Driven Development With Eclipse

Test Driven Development With Eclipse

Elliotte Rusty Harold

Weekend with Experts

December 10, 2005



Test Driven Development

  1. Write a test for a feature

  2. Code the simplest thing that can possibly work

  3. Run the test

  4. Test passed ? goto 1 : goto 2

Test Driven Development

Out of the Box

Demo: Complex Arithmetic

Create the Project

Your first test method

Writing the Complex class

Run the test

  1. Select ComplexTest.java in the Package Explorer

  2. Context Menu/Run/JUnit Test

  3. The test fails!

You want your tests to fail the first time you run them. That's how you know they're testing what you want them to test.

Debug until the test passes

Simplest thing that could possibly work:

    public Complex add(Complex z2) {
        return new Complex(2, 2);
    public long getRealPart() {
        return 2;

    public long getImaginaryPart() {
        return 2;

Write another test

Repaired code

    private int real;
    private int imaginary;

    public Complex(int real, int imaginary) {
        this.real = real;
        this.imaginary = imaginary;

    public Complex add(Complex z) {
        return new Complex(this.real+z.real, this.imaginary + z.imaginary);

    public long getRealPart() {
        return this.real;

    public long getImaginaryPart() {
        return this.imaginary;

Any other obvious bugs?

Adding a feature

Unit Testing

Reinitialization Example


static data is not reinitialized

One of these tests will fail:

    private static Complex w = new Complex(1, 1);
    public void testAddNumberToItselfStatic() {
        w = w.add(w);
        assertEquals(2.0, w.getRealPart(), 0.000001);
        assertEquals(2.0, w.getImaginaryPart(), 0.000001);
    public void testAddNumberToItselfTwiceStatic() {
        w = w.add(w).add(w);
        assertEquals(3.0, w.getRealPart(), 0.000001);
        assertEquals(3.0, w.getImaginaryPart(), 0.000001);


Freeing resources after each test

Assertion Messages

Floating point assertions

As always with floating point arithmetic, you want to avoid direct equality comparisons.

Comparing floating point numbers

    private final static Complex ZERO = new Complex(0.0, 0.0);
    public void testMultiplicationByZero() {
        Complex result = z.multiply(ZERO);
        double tolerance = 0.0;
        assertEquals("Multiplication by zero failed in real part", 
          0.0, result.getRealPart(), tolerance);
        assertEquals("Multiplication by zero failed in imaginary part", 
          0.0, result.getImaginaryPart(), tolerance);

As usual, fix the code after the test fails:

    public Complex multiply(Complex z) {
        return new Complex(
          this.real*z.real - this.imaginary * z.imaginary,
          this.real*z.imaginary + this.imaginary * z.real);

Integer assertions

Straight-forward because integer comparisons are straight-forward:

Object comparisons: asserting object equality

Object comparisons: asserting object identity

Asserting Truth

Asserting Falsity

Asserting Nullness

e.g. testing for memory leak:

    public void testMemoryLeak() throws InterruptedException {
        Complex z1 = new Complex(-2, 0);
        WeakReference ref = new WeakReference(z1);
        z1 = null;

Asserting Non-Nullness

    public void testToString() {
        Complex z1 = new Complex(-2, 0);

Deliberately failing a test

Tests that throw Exceptions

Testing exceptional conditions

    public void testParseComplexThrowsNumberFormatException() {
        try {
            Complex z = Complex.parseComplex("Foo");
            fail("Parsed Foo as complex number");
        catch (NumberFormatException success) {
            assertTrue(success.getMessage().indexOf("Foo") >= 0);

Test Suites

Test Suites

Multiple test classes can be combined in a test suite class:

public class FunctionTests {
    public static Test suite() {
        TestSuite result = new TestSuite();
        result.addTest(new TestSuite(TranslateFunctionTest.class));
        result.addTest(new TestSuite(SubstringTest.class));
        result.addTest(new TestSuite(SubstringBeforeTest.class));
        result.addTest(new TestSuite(SubstringAfterTest.class));
        result.addTest(new TestSuite(LangTest.class));
        result.addTest(new TestSuite(LastTest.class));
        result.addTest(new TestSuite(ConcatTest.class));
        result.addTest(new TestSuite(ContainsTest.class));
        result.addTest(new TestSuite(StringLengthTest.class));
        result.addTest(new TestSuite(StartsWithTest.class));
        result.addTest(new TestSuite(CountTest.class));
        result.addTest(new TestSuite(LocalNameTest.class));
        result.addTest(new TestSuite(NameTest.class));
        result.addTest(new TestSuite(NamespaceURITest.class));
        result.addTest(new TestSuite(SumTest.class));
        result.addTest(new TestSuite(NumberTest.class));
        result.addTest(new TestSuite(RoundTest.class));
        result.addTest(new TestSuite(StringTest.class));
        result.addTest(new TestSuite(BooleanTest.class));
        result.addTest(new TestSuite(CeilingTest.class));
        result.addTest(new TestSuite(FloorTest.class));
        result.addTest(new TestSuite(IdTest.class));
        result.addTest(new TestSuite(TrueTest.class));
        result.addTest(new TestSuite(FalseTest.class));
        result.addTest(new TestSuite(NotTest.class));
        result.addTest(new TestSuite(NormalizeSpaceTest.class));
        return result;

Test Suites Can Be Combined Into Larger Suites

public class JaxenTests {

    public static Test suite() {
        TestSuite result = new TestSuite();
        return result;

What to Test

What Not to Test

To Learn More

Index | Cafe au Lait

Copyright 2005 Elliotte Rusty Harold
Last Modified December 10, 2005