COMP2100/2500 — Software Construction

Lab 3: Testing with Junit

$Revision: 1267 $ $Date: 2013-03-26 14:18:06 +1100 (Tue, 26 Mar 2013) $

Contents of this lab

  1. summary

  2. Preparation

  3. getting started and version control

  4. the challenge: adding new tests

  5. extension task: test data files

  6. extension task: black box testing the API library

Summary

The purpose of this lab class is to get practical experience with testing to debug a given program. Increasing your SVN skills at the same time. The practical experience is in using JUnit testing framework to test a Java based application. We shall also use JUnit for black box testing using some classes from the standard Java API.

Aims



Preparation

Review your notes from

  1. Lecture 09: testing

  2. lecture 10: junit


Exercise 1 – Getting Started

Download the JUnit 4.5 java archive (i.e. a .jar) file and place it in your home bin directory (in $HOME/bin). Set the CLASSPATH environment variable:

(for csh or tcsh)

if ( ~ $?CLASSPATH ) setenv CLASSPATH ; endif
setenv CLASSPATH $CLASSPATH.:$HOME/bin/junit-4.5.jar

(if your shell is bash use

export CLASSPATH="$CLASSPATH:.:$HOME/bin/junit-4.5.jar"

to get the same result).

work in a new directory called lab03 inside your existing lab1 directory. lab1 should be under SVN version control (from your work in lab1), Update it (svn update) - or check it out svn co.

Download the code which was used to illustrate the JUnit testing practices in the lectures, all updated for JUnit 4.x.
Unpack it:

      jar -xvf lab03-junit4.jar 

If you are not using eclipse

compile all of the Java source code files:

     javac *.java

and run each of the tests: for example

    junit.textui.TestRunner TestTriangle

The test classes have a name of the form Test.... Look at the source code of the Test classes, and compare with the corresponding class (for TestTriangle, compare with the class Test).

if you are using eclipse

Create a new eclipse project for lab03.

Choose
Create new project from existing source to use these un-jarred files as this project source (why this way, rather than create project from jar? it is so we can do some version control, in a minute).

Add the junit4 library to the project properties (Project->Properties->JavaBuildPath->Libraries->AddLibrarycode>). Select JUnit4.

You can then select one of the test source files, such as TestTriangle or the test suite AllTests, and RunAs a JUnit test.

Eclipse will create an internal window for junit. and should show the lovely green bar

If this does not work (e.g. JUnit reports"no test cases found") you may have to (a) force recompilation with File->Refresh or (b) change your files/directories/packages structure: ask your tutor.

The test classes have a name of the form Test.... Look at the source code of the Test classes, and compare with the corresponding class (for TestTriangle, compare with the class Test).

revised Tue 7/4/09

1.2. Version control!

You now have to bring the lab03 source files under Subversion control. We do this outside of SVN's automatic tools so that we can see what is happening (we are learning about SVN, not just using it as automagic).

all users

First, remove the .class files (you do not need them in the repository) – [eclipsers: quit eclipse first! so it does not regenerate these .class files while you are not looking]
execute

    rm *.class

Then step up one level (assuming you were in the directory ~/comp2100/labs/lab1/lab03/ to which you downloaded the files), execute

 
   cd ..

and you will be in directory ~/comp2100/labs/lab1.
Now add your newly made lab03 directory to SVN version control:

 
  svn add  lab03

and commit the change to the repository ("add" merely informs the local working copy that you wish to add the new directory)

    svn commit -m'lab 3 junit original'

Change back down into this (new) working copy directory

    cd lab03

That is the normal way to add a new directory and its files into your version controlled repository.
Now for the extra feature: to make svn annotate the source files with the date, the ID of the updating author (that is now you) and the revision number, execute the following command:

 
    svn propset svn:keywords "Date Author Revision" *.java

propset means "set a property": the name of the property is "svn:keywords" and its value is that string.

SVN does something special when a file has properties like this.

Every time you commit and update, the source of the file is changed by SVN: the special string $Author: cwj $ and $Revision: 850 $ in the source file (in this case they are in comments in the class headers) will now expand to the right values of modification date, author, and revision number every time you check the files out.

Having automatic file tags like this is very good practice because it makes a note of the version and a bit of recent history in each copy of the source file, and helps you recover from the problem of too many versions and working copies scattered around.

That is, instead of the original generic comment

 
* @author  $Author: cwj $
* @version $Revision: 1267 $
* $Date: 2013-03-26 14:18:06 +1100 (Tue, 26 Mar 2013) $

you will get a "personalised" comment like

* @author $Author: cwj $
* @version $Revision: 1267 $
* $Date: 2013-03-26 14:18:06 +1100 (Tue, 26 Mar 2013) $

We use this in many of our programs and webpages for this course.

Exercise 2 – adding new tests

Look inside the Triangle.java source file. It contains several new methods which were not mentioned in lectures. The test code does not yet check the correctness of the new methods. Read the comments inside the source code, understand what the new methods do, and work out different inputs and expected outputs for each method.

This is the important step of designing test cases.

Use your newly designed test cases, and write new test methods in the TestTriangle.java file. According the JUnit prescription, you have to employ assertions from the Assert class.

You don't have to fully understand the implementation of methods in the Triangle class. It's enough to understand the "contract" of the methods, and to construct the expected output (the return value) for a given input (the actual parameter values taken by the method). For example, one of the new methods in the Triangle class is isInside(Point p) which returns a boolean value depending on whether the Point p lies inside the this triangle, or outside. The implementation of this method involves although elementary, but quite complex algorithm (and I am not quite sure that I've got everything right). Your task would be to test this implementation by applying several "obvious" test cases when you can be certain about the outcome. Start with a simple case and gradually make them more general. Use simple drawing to help yourself. For instance, create a triangle

    Triangle t = new Triangle(new Point(0,0), new Point(1,0), new Point(0,1)); 

It's quite easy to see that any point with the positive coordinates (x,y) which satisfy the inequality

    x + y <= 1

lies inside the triangle t. Also, as you can easily see, if either of the (x,y)-coordinates of Point p is greater (or smaller) than the corresponding coordinate of any of the triangle's three vertices, we can be sure that the point p lies outside of the triangle.

Use a calculator (on a mobile phone or in the Linux box in the front of you), if necessary to construct more sophisticated tests. Think of the boundary values for the test. How to handle a situation if the point lies exactly on the triangle border? What if the triangle is degenerate?

Other classes (Point, PlanarVector, Complex) also have not been fully tested. Write new methods in the corresponding test classes.

Of course, your tests cannot be exhaustive (and should not aim to be). Write test methods, compile the test class, call the TestRunner (or RunAs JunitTest in eclipse) and see your tests in the Swing GUI window.


Group scramble

When you have explored the program with a few tests, work with your neighbours as a small ad hoc collaborative team: design a testing strategy. The aim is to discover what is wrong with this code, as quickly as possible, using a small number of tests. The team is there to discuss strategy and use the smartness of the group. It'll be good if you can find an error in the "production" code using the JUnit tests.
Be ready to report the test failures and what was your strategy, to the tutor and to the class.


Three extension exercises

These exercises illustrate some more powerful extensions in technique and in theory to setting up test cases and applying JUnit.
Choose one or more that interest you for practical work. These exercises can also be used as study exercises on the design of test cases.

Extension exercise 3* — using test data files

From working with TestTriangle.java, you can agree that creating the test data can be time and intellect consuming. Often these data are obtained from real experiments. Or, using different algorithms (which are known to be correct, but you are trying to implement a new one and use the old for testing). One way or another, these test data represent valuable assets. They can be stored somewhere in a separate file, or even in a secure database.

Write a file which contains as many lines as you have test value pairs (input and expected output). Write a test method which can be used on such test data files. Namely, inside the test class write a setUp() method which will open a stream from the test file, will read a line, parse it by selecting the input value and expected output value, store these values in the local object item of TestItem class (which can hold a pair of data accessible by getInputValue() and getExpectedOutput() methods), and put this TestItem instance into an ArrayList (or another suitable class which implements the Collection interface) object testData (by testData.add(item)). When all the test data from the test file are read, the setUp() method will end. The testData will then be used in a test method, which will contain a loop for iterating through the Collection object testData. For every element (item) in the testData, the input and expected output values will be extracted and used in the actual test involving the call for an appropriate assert method. The tearDown() method can be used to close the stream from the test data file, and reset the variables.

When the type of the test data and the test file format change, only partial recoding in the setUp() method will be required. Using Java 1.5 generic features can keep the amount of re-coding relatively small.


Extension exercise 4* – testing API classes

The JUnit approach was originally conceived for white box testing: the author of the tests can see the source code of methods of the class. However, it can be also used for black (grey) box testing, when the production code is not available, but the unit (class) contract and specification allows to formulate test cases. For example: in this exercise, you will take one of the standard classes from, eg, java.util, or java.util.regex packages, and test it using the JUnit framework. I suggest you choose either the java.util.Scanner class, or java.util.regex.Pattern class, and write the test classes TestScanner, or TestPattern, correspondingly.

For example, look up the java.util.Scanner API, and see what methods this class has to offer.
One of the methods is next(String pattern) which returns the first substring matching the specified string pattern, and advances past the input that matched the pattern. Write several strings with simple patterns to test the described behaviour. (Boundary cases? Equivalence cases? What test design principle applies?)

A similar method next(Pattern pattern) allows you to handle more general case of a regular expression given by the Pattern instance pattern. Extend your tests to this method.


Extension exercise 5* – gaga colour utility

Design and implement an efficient JUnit test set for the gaga colour utility class methods in the assignment distribution, to make an improvement on the few tests that are included in the class main method. You may like to provide tests for the cases that gag does not yet handle: contributing these tests (in your assignment submission) would be a contribution to the ongoing development of gaga.




    Copyright © 2006–2012 Ian Barnes, Alexei Khorev, Chris Johnson, The Australian National University
    $Revision: 1267 $ $Date: 2012-03-24 17:41:31 +1100 (Sat, 24 Mar 2012) $ $Author: cwj $ Feedback & Queries to comp2100@cs.anu.edu.au