Rational: ex03

creating a jar file, automatic testing with junit, creating and publishing javadoc

Part of a series of tutorial articles about a Rational class.

On website: https://ucsb-cs56-pconrad.github.io/tutorials/rational_ex03/

Code examples referred to on this page can be found here: https://github.com/UCSB-CS56-pconrad/cs56-rational-ex03

cs56-rational-example/ex03

In this example, we will add three new features to our build.xml file

The second of those will also require a new class, RationalTest.java, a class that exists only for the purpose of collecting test cases for all of the constructors and methods of Rational.java.

This is a practice we’ll try to follow whenever developing a class that other parts of the code rely on for correctness. That is, whenever possible, every class Foo.java should have a FooTest.java that goes along with it.

Adding an Ant task to make a .jar file

We add the following section to our build.xml file to create a .jar file of our project. This jar file is nothing more than a ZIP archive of .class files along with some metadata that tells us which class is the default main to run if we ask to “run the .jar file”.

  <target name="jar" depends="compile">
    <jar destfile="build/rational.jar">
      <fileset dir="." includes="*.class"/>
      <manifest>
	<attribute name="Main-Class" value="Rational"/>
      </manifest>
    </jar>
  </target>

To run this new target, we use:

ex03 pconrad$ ant jar
Buildfile: /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/build.xml

compile:
    [javac] Compiling 2 source files to /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03

jar:
      [jar] Building jar: /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/build/rational.jar

BUILD SUCCESSFUL
Total time: 0 seconds
ex03 pconrad$ 

We can then run the file with this command:

ex03 pconrad$ java -jar build/rational.jar 
r.getNumerator()=5
r.getDenominator()=7
ex03 pconrad$ 

Notice several things:

JUnit tests

One of the purposes of a jar file is to be able to distribute java code to others. This is a common way that third-party libraries are added into a project. Rather than incorporating all of the source code for a project and recompiling it, we add a .jar file into the project.

One of the most useful third-party libraries–that is a library of useful code that doesn’t come standard with the Java distribution from Oracle–is a library called JUnit.

Unit testing and test driven development is a large topic, and we are not going to give it a full treatment in this tutorial.

Instead, we’ll just show the mechanics of how to incorporate JUnit testing into the project. For a more detailed treatment of Test Driven Development (TDD), JUnit, and testing practices, you’ll need to look elsewhere–for example, these articles from the CS56 web site on TDD and JUnit.

The first thing we’ll do is create a subdirectory called lib in our ex03 directory, and copy the latest version of the Java JUnit .jar into this directory.

We use the command line tool wget to copy the file from the URL shown. You could also use a web browser and do a save as if you don’t have wget on your system. The command line tool curl is another option.

ex03 pconrad$ wget http://www.cs.ucsb.edu/~pconrad/cs56/lib/junit-4.8.2.jar
--2016-06-18 17:13:15--  http://www.cs.ucsb.edu/~pconrad/cs56/lib/junit-4.8.2.jar
Resolving www.cs.ucsb.edu... 128.111.27.14
Connecting to www.cs.ucsb.edu|128.111.27.14|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 237344 (232K) [application/x-java-archive]
Saving to: 'junit-4.8.2.jar'

junit-4.8.2.jar            100%[======================================>] 231.78K  13.5KB/s    in 21s     

2016-06-18 17:13:39 (11.1 KB/s) - 'junit-4.8.2.jar' saved [237344/237344]

ex03 pconrad$ 

After doing this, in the lib directory, we have the file junit-4.8.2.jar:

ex03 pconrad$ pwd
/Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/lib
ex03 pconrad$ ls
junit-4.8.2.jar
ex03 pconrad$ 

(Note that as of this writing (06/18/2016), there is a much later version of JUnit available, namely JUnit 4.12. For this tutorial, I’m using 4.8.2 because 4.12 relies on an additional .jar file called hamcrest-core.jar version 1.3. Before we start getting into .jars that need other .jars, its probably better to just go ahead and move to Maven.)

Ok, now that we have this .jar file, what do we do with it? There are several steps to getting to the point where we can write tests:

  1. Write some code that uses JUnit.
  2. Get that code to compile (that means putting the JUnit .jar in the classpath of the Ant javac task inside the ant compile target.)
  3. Add a test target that calls the junit Ant task to run the tests.

We’ll do each of those next.

1. Write some code that uses JUnit

A simple test we can do is to see if our constructors and getters are working properly. We’ll set up a few objects and then see if the getters return the expected values.

We’ll add a file called RationalTest.java to our project, with these contents:

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class RationalTest {
  @Test
	  public void test_getNumerator_1() {
	  Rational r=new Rational(4,5);
	  assertEquals(4, r.getNumerator());
  }

  @Test
	  public void test_getNumerator_2() {
	  Rational r=new Rational(7,3);
	  assertEquals(7, r.getNumerator());
  }

  // In the real file, two more tests follow here...

}

Clever students may have noticed: one of the challenges right away is that the tests are not exactly testing only one unit of code: they work only if both the constructor and the getters are correct. (If you didn’t notice that, or it didn’t both you, no worries.)

The unit tests that we write here are not necessarily the best examples of good testing practice. These are here more to illustrate the mechanics of getting testing working.

2. Get the JUnit code to compile

When we try to compile this, we’ll get some errors:

ex03 pconrad$ ant compile
Buildfile: /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/build.xml

compile:
    [javac] Compiling 3 source files to /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03
    [javac] /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/RationalTest.java:1: error: package org.junit does not exist
... [Lots more errors here... ]

The reason is that we can’t import JUnit unless JUnit is in the classpath. JUnit is an add-on, not part of the standard Java library.

To get it into this classpath, we introduce this bit of code into our build.xml. It says to look first in the current directory, then in the junit .jar file. (The Java system libraries are always included without us having to do anything.)

  <path id="project.class.path"> 
    <pathelement location="."/>                                                       
    <pathelement location="lib/junit-4.8.2.jar"/>    
  </path>

We then tell the javac task to use our classpath, by modifying it like this. Note that the classpath element is a nested element.

 <javac srcdir="."
           destdir="."
           includeantruntime="false">
      <classpath refid="project.class.path" />
 </javac>

Now we can compile:

ex03 pconrad$ ant compile
Buildfile: /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/build.xml

compile:
    [javac] Compiling 3 source files to /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03

BUILD SUCCESSFUL
Total time: 0 seconds
ex03 pconrad$ 

But how do we run the tests? There’s a special ant task for that.

Add a test target to run the tests

We’ll add this target to our build.xml file. Note that it depends on the compile target.

  <target name="test" depends="compile" description="run JUnit tests">
    <junit haltonerror="no" haltonfailure="no">
      <classpath refid="project.class.path" />
      <batchtest fork="yes">
	<fileset dir=".">
	  <include name="*Test.java"/>
	</fileset>
      </batchtest>
      <formatter type="brief" usefile="false" />
    </junit>
  </target>

To understand all of this, it may be helpful to refer to the reference for the JUnit Ant Task, here: https://ant.apache.org/manual/Tasks/junit.html

For now, the important thing to know is that we run our tests by typing ant test:

ex03 pconrad$ ant test
Buildfile: /Users/pconrad/github/UCSB-CS56-M16/cs56-rational-example/ex03/build.xml

compile:

test:
    [junit] Testsuite: RationalTest
    [junit] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.059 sec
    [junit]

BUILD SUCCESSFUL
Total time: 0 seconds
ex03 pconrad$ 

That’s it for example ex03.

In the next tutorial, Rational: ex04, we’ll:

On website: https://ucsb-cs56-pconrad.github.io/tutorials/rational_ex03/