Comp 212 Lab 3: JUnit, JavaDoc, Package, Immutable Lists


Introduction

This tutorial covers:


I. Unit Testing with  JUnit (30 min)

Extreme Programming (XP) is a software development methodology that is "very hot" these days and is currently embraced by the software industry.  One key element of XP, called "unit testing", is the idea of writing test code for functions (or procedures or object methods) before the functions (or procedures or object methods) are even written.  (Don't ask me how to write test code for the test code themselves!  The whole thing is "kinda" suspiciously recursive with no well-defined base cases.)  The test code becomes in effect the "documentation and specification" of the behavior of the functions (or procedures or object methods) in code form!  Each time a function (or procedure or object method) is modified, it must pass its existing test code.  Each time a test code for a function (or procedure or object method) is modified, the corresponding function (or procedure or object method) may have to be revised to satisfy the new specification.

JUnit (www.junit.org) is an open source framework developed to support the above concept of unit testing for Java programs.  This tutorial will lead you through a simple example of how to write unit test code in developing a (simple) Java program with only one class.

Step 0. 

Run DrJava.  We will do all development in DrJava since it has very nicely integrated JUnit with its development environment.  You may want to peruse the online help for DrJava and read about Testing using JUnit there.

Step 1. 

Suppose we want to model the notion of a smart person who knows his/her birthday and can compute the number of months till his/her next birthday given the current month.  For our purpose, a month can simply be represented by an integer, which in Java  is called int..  We start by writing stubbed code for the class Person  that is to represent our smart person.  

public class Person {

    /**
    * Computes the number of months till the next birthday.
    */
    public int nMonthTillBD(int currentMonth) {
        // to do
    }

}

Notice in the above there is really no concrete code.  As a matter of fact, the above would not compile.  Now we must abandon everything and start writing test code for nMonthTillBD(...)

Step 2. 

To write test code using the JUnit framework, in the simplest case all we have to do is:

DrJava is very nice to you and will create the above stub class for you if you know what to click: 

import junit.framework.*;

public class Test_Person extends TestCase {

    public void test_nMonthTillBD() {

        Person peter = new Person(9); // a person born in September.

        assertTrue("peter is null!", !peter.equals(null));
        assertEquals("Calling nMonthTillBD(2).", 7, peter.nMonthTillBD(2));
        assertEquals("Calling nMonthTillBD(9).", 0, peter.nMonthTillBD(9));
        assertEquals("Calling nMonthTillBD(12).", 9, peter.nMonthTillBD(12));
    }
}

Note that in the code for test_nMonthTillBD(), we arbitrarily decide that we must have a constructor for Person as shown in the code in order to instantiate any concrete Person object to be born with a given birth month.  Also the test covers three cases:

When you compile the above code in DrJava, clearly it won't compile.  So you will have to go in and fix the code for Person to make the test code compile.

Step 3.

Fix the code for Person  until Test_Person compiles!

public class Person {
    private int _bMonth;

    public Person(int birthMonth) {
        _bMonth= birthMonth;
    }

    /**
    * Computes the number of months till the next birthday.
    */
    public int nMonthTillBD(int currentMonth) {
        return 0; // to do
    }
}

Step 4.

After you have cleaned up your code for Person as shown in the above, you should be able to compile Test_Person.  With Test_Person open, click on the Test button in DrJava tool bar.

What do you see?  Something has failed!  The formula for the number of months till the next birth day seems to be the culprit.  We will pretend ignorance and fix the "bug" in two steps.

Step 5.1

Change the formula to

    public int nMonthTillBD(int currentMonth) {
        return _bMonth - currentMonth; // to do
    }

Compile all and test again.

Still we have errors.

Step 5.2

Change the formula to

    public int nMonthTillBD(int currentMonth) {
        return (_bMonth - currentMonth + 12) % 12; // to do
    }

Compile all and test again.  Now everything should pass!  You may now remove the TO DO comment from the code of nMonthTillBD.

In XP programming, only after a method has passed its unit test that you are allowed to proceed to another one.

Additional Reading:

 

I. Java Documentation Style (15 min)

The Java Development Kit (JDK) comes with a tool called JavaDoc.  This tool will generate documentation for Java source code with comments written in accordance with the Java documentation style.   The following links show more examples.  You do need to spend time outside of the lab to study them.

Click here to download a single jar file (listSource.jar) containing sample Java code into your own directory.  It includes Java source code for a version of lists discussed in the past few lectures.  Extract the files from the jar file using the command:

jar xf listSource.jar

Section III below will provide a more detailed discussion of the JDK's JAR utility.

Use DrJava to look at both the code and the comments, which follow the Javadoc conventions.  The following is a very short summary of the Javadoc conventions.

Creating javadoc using DrJava:

In DrJava, 

Now change the javadoc Access level in the javadoc Preferences to private and generate javadoc again.  What is  the difference?

Creating javadoc (1.1 version) using StructureBuilder

You can generate javadoc using the Tools/Generate Documentation menu in StructureBuilder.  What you get is the UML class diagram diagram together with the javadoc (version 1.1 style).  You may use this tool to generate javadoc and UML diagrams for all of the assignments.

 


II. Package (15 min)

A Java package is a grouping of classes similar to the notion of a directory is a grouping of files. Packages are used to help avoid name clashes and to hide particular pieces of code from the clients. A package has a name, such as utility or java.lang.util. In general, a package name is a series of strings of alphanumeric characters (starting with an alphabetic character) and separated by periods. To make a java class part of a particular package, say scheme, you must add the declaration package scheme; to the very top of the class source file.

Also, you will need to put the file in the directory structure that mirrors the package name. For example, the java classes that belong to the package scheme should be in a directory also named scheme. If you don't do this, it will still compile, but it won't run correctly.

Exercises:

  1. Add the package scheme; declaration to the top of IList.java. You need to create a subdirectory called scheme and move IList.java into it.

    Now compile using

         javac scheme/IList.java
         
    Note that you should always compile from your project's main directory. If you compile from within a package subdirectory, it doesn't find all the supporting definitions.

    We can't run anything yet, because that's just a piece of the whole program.

  2. Add the package scheme; declaration to the top of IEmptyList.java, INEList.java,  EmptyList.java , NEList.java and ListOps.java, and move them into the scheme subdirectory. Do not make Test_List.java part of the package. Test_List.java  does not have a package name, and is thus said to be in the no-name (or default) package.  

    Also, remove the public access from the EmptyList and NEList classes. By default, a class is "package-private", i.e., it is known within the package, but not from outside. If you try to compile Test_List.java now, you will get an error message. Try it to see what happens.

    You need to add the statement import scheme.*; to the top of Test_List.java  to indicate to the compiler that you are using all the public classes in that package. Try to compile it again.

    You should see a few error messages saying that you can't use EmptyList.java and NEList.java because these classes are not public. This is because the Test_List class is not part of the scheme package. One way to resolve this problem by making Test_List part of the scheme package. A class of a package can access all the classes (public or "package-private") in the package. However this is not a good solution in general because a client may be using many classes from different packages, but not class can be part of more than one package. A better solution is to use a "factory".  We will discuss factories in another lab.  For now, just make EmptyList.java and NEList.java public again, and recompile Test_List.java . You should get no error.  Try to run Test_List.java  now by click the Test button in DrJava.


III. List Exercises (30 min)

In the following exercises, assume NEList contains Integer objects only.   Integer is called the wrapper class for int.  You will need to use its intValue() method and its constructor Integer(int i).  The detailed documentation for Integer can be found at: http://java.sun.com/j2se/1.4/docs/api/java/lang/Integer.html.

Add the following methods to IList and its appropriate subclasses as specified.

  1. public int sum(): compute and return the sum of the Integer elements in this IList.  Add the method test_sum to the Test_List class.
  2. public boolean containsAllNonNegative(): returns true if all the Integer elements in this IList are non-negative (>= 0), false otherwise.  Add the method test_containsAllNonNegative to the Test_List class. 
  3. public int nonNegCount(): computes and returns the number of non-negative Integer elements in this IList.  Add the method test_nonNegCount to the Test_List class. 
  4. public boolean hasMostlyNonNeg(): returns true if this IList contains more non-negative (>= 0) Integer elements than negative (< 0) ones, false otherwise.  Add the method test_hasMostlyNonNeg to the Test_List class. 

You will probably not have enough to do all of the above exercise.  Continue working on them off line.


 
Prepared by Dũng X. Nguyễn  
last revised 01/25/2004