Software Testing: Getting started with Eclipse and JUnit (JUnit 3)

The purpose of this tutorial is to ensure that you are comfortable with the Eclipse/Java/JUnit tools on DICE (or whichever alternative tools that you choose to work with).

A brief note on JUnit 3 and JUnit 4

There are two versions of JUnit around, 3 and 4. JUnit 4 is more modern, and so generally to be preferred. However, JUnit 4 requires language features introduced in Java 1.5, so the more backward-compatible JUnit 3 is still in widespread use, and it may be interesting for you to know the basics of its operation. Also, of particular note to those of you who prefer not to use the Eclipse environment, the version of Ant installed on DICE, 1.6.5, is incompatible with JUnit 4. Consequently if you want to use Ant to run your builds from the command line you'll need to write any tests you create for this course using JUnit 3 or come up with some other kind of personal workaround.

So unless you have strong personal reasons for doing otherwise, I'd recommend that you do any Java work you need to do for the course in Eclipse, and write your tests in JUnit 4: it's slightly easier, and requires less typing.

Note that this is the JUnit 3 version of this tutorial — the JUnit 4 version is here!

Source code

Recall the Triangle source code we looked at in class — first the badly-implemented Triangle class itself:

Source for st.Triangle:
package st;

public class Triangle {

  private int p; // Longest edge
  private int q;
  private int r;

  public Triangle(int s1, int s2, int s3) {
    // Ensure that p is the largest of the three.
    if(s1 > s2) {
      q = s2;
      if(s1 > s3) {
        p = s1; r = s3;
      } else {
        p = s3; r = s1;
      }
    } else {
      q = s1;
      if(s2 > s3) {
        p = s2; r = s3;
      } else {
        p = s3; r = s2;
      }
    }
  }

  public boolean isScalene() {
    return p > 0 && q > 0 && r > 0 && p < q + r &&
            (q < r || q > r);
  }

  public boolean isEquilateral() {
    return p == q && q == r;
  }

}

Then the TriangleTestJ3 unit test:

JUnit 3 source for st.TriangleTestJ3:
package st;

import junit.framework.TestCase;

public class TriangleTestJ3 extends TestCase {

  private Triangle t;

  public void setUp() {
    t = new Triangle(3, 4, 5);
  }

  public void testTriangle() {
    fail("Not yet implemented");
  }

  public void testIsScalene() {
    assertTrue("t not scalene!?!", t.isScalene());
  }

  public void testIsEquilateral() {
    assertFalse("t unexpectedly equilateral!", t.isEquilateral());
  }

}

And finally the AllTestsJ3 test suite:

Source for st.AllTestsJ3:
package st;

import junit.framework.Test;
import junit.framework.TestSuite;

public class AllTestsJ3 {

  public static Test suite() {
    TestSuite suite = new TestSuite("Test for st");
    //$JUnit-BEGIN$
    suite.addTestSuite(TriangleTestJ3.class);
    //$JUnit-END$
    return suite;
  }

}

Things to do

Add tests

Think of a series of test inputs and the results that you'd expect for them, then create the appropriate tests. As I explained in class, the test fixture mechanism is clumsy for instantiating and testing a lot of objects, so you might prefer to get rid of the private Triangle t; and setUp(), and do something like this:

Testing lots of Triangles:
public void testIsEquilateral() {
  Triangle t = new Triangle(4, 5, 6);
  assertFalse("(4, 5, 6) unexpectedly equilateral!", t.isEquilateral());
  t = new Triangle(1, 1, 1);
  assertTrue("(1, 1, 1) unexpectedly not equilateral!", t.isEquilateral());
  …
}

You could also add a toString() method to Triangle in order to help with debug messages (this tutorial on Java's toString() method might be of use).

Fix the implementation

These tests will quickly show that isScalene() is incorrect. Fix it.

Enhance the implementation

It's really an error to allow construction of bad triangles, so it makes sense to test these bad inputs in the constructor and throw an exception of some kind for non-triangle parameters. Do this, including adding a BadTriangleException to your implementation. You may need to add some throws clauses to your code. You may also find that after making these enhancements, you can simplify the isScalene() test.

Test the enhancements

As demonstrated in class, you can test that error conditions are detected and exceptions get thrown correctly too:

Testing to see that exceptions are thrown:
public void testTriangle() {
  try {
    // Some code which should cause an exception:
    Triangle q = new Triangle(0, 0, 0);
    // If we get here then the code didn't cause an exception,
    // and so the test has failed.
    fail("Exception not thrown: bad triangle accepted!!!");
  } catch(ParticularExceptionWeAreTestingFor e) {
    // If we get here then the exception was thrown correctly.
    // We do nothing, and let successful execution continue.
  }
  …
}

Implement a set of tests for the Triangle constructor.


Version 1.2, 2011/01/14 00:58:26


Home : Teaching : Courses : St : 2010-2011 

Informatics Forum, 10 Crichton Street, Edinburgh, EH8 9AB, Scotland, UK
Tel: +44 131 651 5661, Fax: +44 131 651 1426, E-mail: school-office@inf.ed.ac.uk
Please contact our webadmin with any comments or corrections. Logging and Cookies
Unless explicitly stated otherwise, all material is copyright © The University of Edinburgh