Test Driven Development and JUnit

One of the big changes in software engineering, and part of the agile methodology shift, is Test Driven Development (TDD). This puts writing tests near the front of the development process, not at the end as in older methodologies.

Tests contribute to design. Experience with TDD has shown that writing the tests first has many benefits, but an important one is that it contributes to the design process. Thinking about what to test involves thinking about how the program works.

Confidence to make changes. Another advantage is that once you have a lot of tests, you’re much less afraid to improve (“refactor” in the current jargon) code. Make a few changes, then rerun the tests.

JUnit – an automated testing tool

To make TDD easy, a number of frameworks have been written. The most popular, and indeed the de facto, tool for Java is JUnit (www.junit.org). JUnit is hugely popular with support in all the IDEs.

Where to find out more?
Take a look here JUnit Test Infected: Programmers Love Writing Tests

Using JUnit is easy
Using JUnit is quite easy; there are only a few things to learn. NetBeans makes it even easier by automatically doing most of the work for you. You can get either GUI or text feedback on how your tests performed. There’s a lot of pleasure in seeing the green bars grow in the GUI output, but in an attempt to keep things really simple, it appears that JUnit version 4 will support only text output. The authors of JUnit are dedicated to simplicity in programs, so this removal of features is a wonderful contrast to normal bloatware.

Executing JUnit Tests

The following snippet is basically how I run my JUnit tests:

<junit printsummary="yes" showoutput="no" fork="true">
	<formatter type="xml"/>
	<classpath refid="test.class.path"/>
	<batchtest  todir="${test.results}">
	<fileset dir="${test.dir}" includes="**/*TestSuite.java"/>
	</batchtest>
</junit>

Of course, for this to work, the junit jar must be in either ant’s lib directory or referenced in the property test.class.path . This will recursively find and execute all the test suites (I use the naming convention of FooTestSuite.java to denote my test suites) in the test.dir directory. The results are stored as XML and can later be converted to an HTML report using junitreport

(http://ant.apache.org/manual/OptionalTasks/junitreport.html).

JTiger

JTiger is a newer framework which relies heavily on the new facilities of 1.5. The most obvious to the user will probably be the annotations and static imports. JTiger requires no external configuration files to execute the tests. For me, JTiger passed the ten minute test easily. Using the user guide, I was able to convert my JUnit test easily and have tests running quite quickly.

Test Example

Below is the JTiger version of the unit test we’ve already seen. I’ll list it here and analyze it in the following sections.

package com.antwerkz.testing.jtiger;

package com.antwerkz.testing.jtiger;

import com.antwerkz.testing.Person;
import com.antwerkz.testing.PersonManager;
import com.antwerkz.testing.Department;

import static org.jtiger.assertion.Basic.assertEqual;
import static org.jtiger.assertion.Basic.assertFalse;
import static org.jtiger.assertion.Basic.assertNotNull;
import static org.jtiger.assertion.Basic.assertNull;
import static org.jtiger.assertion.Basic.assertTrue;
import org.jtiger.framework.SetUp;
import org.jtiger.framework.Test;
import org.jtiger.framework.Category;
import org.jtiger.framework.Fixture;
import org.jtiger.framework.Ignore;
@Fixture("Tests various aspects of Person functionality")
public class PersonTest {
    private Person _person;

    @SetUp
    public void setUpTestData() {
        _person = PersonManager.create("John", "Cleese");
        Department department = new Department("Ministry of Silly Walks");
        _person.setDepartment(department);
        _person.setSalary(50000d);
    }

    @Category("manager")
    @Test(value="managerGets",
        description="Tests to ensure that we can get from the manager correctly")
    public void managerGets() {
        assertNotNull(PersonManager.get(_person.getID()));
        assertNull(PersonManager.get(-12345L));
    }

    @Category("manager")
    @Test(value="manager removes", description="Tests removes from the manager")
    public void managerRemoves() {
        assertTrue(PersonManager.remove(_person.getID()));
        assertFalse(PersonManager.remove(-12345L));
    }

    @Category("bean")
    @Test(value="attribute tests", description="Test the attribute getters and setters")
    public void attributes() {
        Person person = PersonManager.get(_person.getID());
        assertEqual(_person.getDepartment(), person.getDepartment());
        assertEqual(_person.getSalary(), person.getSalary());
        assertEqual(_person.getFirstName(), person.getFirstName());
        assertEqual(_person.getLastName(), person.getLastName());
    }

    @Category("bean")
    @Test(value="departments", description="Test the relationships")
    public void departments() {
        Department dept = PersonManager.get(_person.getID()).getDepartment();
        int count = dept.size();
        PersonManager.get(_person.getID()).setDepartment(null);
        assertNull(PersonManager.get(_person.getID()).getDepartment());
        assertTrue(count == (dept.size() + 1));
    }

    @Category("manager")
    @Test(value = "ignored test", description = "this test should be ignored")
    @Ignore
    public void ignoreMe() {
        assertTrue(false);
    }
}

This test is basically the JUnit version ported over to JTiger. I have renamed the test methods to highlight the fact that method names can be whatever makes sense to the developers. As one can see the test is very simple. There is not much to the test code and it requires no configuration beyond what is shown here. There are two categories of tests defined here manager and bean and one of the manager tests is ignored. Notice the static import of the assert methods. While the static imports are not necessary, most developers will probably use them to improve readability.