Test First Development
DUE:
11:59PM, Sunday 2 September 2012
25 points
Objectives
- Review Java
- Become familiar with environment (java, javac, eclipse)
- Become familiar with JUnit
- Practice test-first development
This assignment was originally developed for CS414 by Ken Shrum. It has
been adapted for this class. Make a note of the version of JUnit that you
are using so that we can grade your program with the same version.
Getting started
Read the notes on Testing, TDD, and JUnit; Chapter 4 in the Fowler text;
Test
Infected; and the
JUnit
Cookbook.
These examples are mostly based on JUnit 3.8, which
may not work with JUnit 4.x.
JUnit details can be obtained from
www.junit.org.
JUnit is already
integrated with Eclipse, thereby providing several advantages. Environment
variables are set up "automagically". Test execution is tied to the Eclipse
debugger, so you can view what went wrong. Test driver skeletons are
generated; you just need to fill in the test cases.
Tasks
Certain games use a rectangular grid for the world, and allow the world
to "wrap" from top to bottom and from left to right. Conceptually,
this makes a doughnut-shaped world: if you keep going "North" you eventually
wrap back around to where you were, and if you keep going "East" you similarly
wrap back around. Note that going North is the +y direction, and going
East is the +x direction.
We're going to implement a couple of classes to
hide the details of the representation from client code.
-
Implement class World, which represents an n*m grid of Objects, where the
coordinates wrap as described above. Note that these Objects refer to instances
of the class java.lang.Object.
-
give it a constructor that takes n and m, where n gives the number of locations
possible in the West-East direction, and m gives the number of locations
possible in the South-North direction.
-
give it a second constructor that takes just n, meaning an n*n grid.
Use the "this" form to implement it in terms of the first constructor
-
give it a method get(int x, int y) which returns the object at x, y in
the grid, without wrapping. Declare this method protected rather
than public. Don't check x and y for being within range, just index
the underlying array
-
this use of protected allows other classes in the same package (like Coordinate)
to call the entry point, but not classes outside of the package
-
similarly, give it a protected method put(int x, int y, Object o) to place
the Object o in the grid. Declare this method protected rather
than public. Don't check x and y for being within range, just index
the underlying array. Do not wrap.
-
give it a method get(Coordinate c) which returns the object at c, implemented
in terms of the get() method in the Coordinate class.
-
give it a method put(Coordinate c, Object o) which puts the object o at the
x,y position indicated by Coordinate c.
-
give it a simple toString method that returns something like "World(n,
m)"
-
do not implement equals or hashCode
-
Implement class Coordinate, which represents an x,y position in a particular
2D world (where x and y are ints). The x,y in a Coordinate must always
be valid, i.e. in the 0..n-1, 0..m-1 space
-
give it a constructor that takes a World, x, and y. This constructor
must handle wrapping
-
give it a method get() which returns the object at the specified Coordinate
in the World this Coordinate is using
-
give it a method put(Object o), which replaces the Object in the grid with
the Object o provided as the argument.
-
give it a method equals(). Two Coordinates are equal
if they represent the same location in exactly the same World object.
You must compare the Worlds for identity using ==
-
give it a method hashCode(), which returns the sum of values of x and y and the
hashcode of its
World object.
-
give it methods north(), south(), east(), and west() that return the adjacent Co
ordinate
in those particular directions. North is the +y direction, East is
the +x direction, etc. These methods must handle wrapping
-
give it a method toString() that returns something like
"Coordinate(x,y) in World(n,m)"
Remember that you're doing test-first development. Write
a unit test first, then write the code that will pass it. Iterate
on this. You'll turn in your test code in addition to the
code for World and Coordinate classes.
Any object can be stored in the grid. For testing purposes, feel free
to choose something that is simple to compare with the expected object
returned by a get method. You can use instances of Integer or String,
for example.
Deliverables
All the classes that you write must be in a package called cs414.a1.yourEID.
Submit a jar or a zip file, A1-youreID.jar or A1-youreID.zip, which
includes the following:
- WorldTest.java: Contains tests for the class, World
- World.java
- CoordinateTest.java: Contains tests for the class, Coordinate
- Coordinate.java
- TestAll.java: Defines the test suite for all the unit tests of this
homework.
- overview.txt: a very short overview paper, providing
information that is not readily available from reading
the code things that gave you trouble, etc. This paper
should be plain ASCII text.
The folder (or directory) hierarchy must be cs414/a1/yourEID. The Java source
files must be present in the yourEID folder of the hierarchy. When you create
the jar/zip file, build it from the top of the directory hierarchy. The
submitted file must correctly unpack the .java files into a subdirectory
cs414/a1/yourEID. The grader will cd to the appropriate directory, run
javac *.java, and launch JUnit on cs414.a1.yourEID.TestAll. In addition,
the grader will read all of your code, and may run it by hand against sample
inputs.
Submit
- It's extremely important to submit your work using the specified form.
If your work does not meet that form, you will receive no credit for the
assignment. This may seem harsh. However, the grader will have a relatively
large number of assignments to grade. Guessing how to unpack and compile
individual assignments can take a lot of time, and is an unfair burden on
the GTA.
- Make sure you must submit all of your test code in addition to the code
for all your classes.
- Be certain that all of your code is within a package, as described in the
instructions.
- Submit a single jar or zip file, submitted using Assignment Submission in RamCT.
Grading criteria
- Functionality of World and Coordinate (implement methods correctly): 5+5 points
- Functionality of test classes: (5+5) points
- Testing strategy: 3 points
- Programming style: 2 points
Up to 5 points may be deducted for not following the packaging structure or
names used for the classes and the methods of each class.
Tips
Click here for detailed steps on using Eclipse
to work on the assignment and create the final jar file for submission. Note
that the screenshots may differ based on the version of Eclipse used and
certain other configuration and environmental factors. Also, please use
cs414 instead of cs414dl in your package names.
In case you are using the command line to edit and compile your programs,
here's an example. Bob codes up WorldTest.java, World.java,
CoordinateTest.java, Coordinate.java, and TestAll.java. He tries them out,
and is satisfied that they work. Bob verifies that the .java files build
cleanly by doing an rm *.class (Be careful not to delete your source
files by accident!), and javac *.java. Bob verifies that all of
the unit tests are running and pass at 100% by using JUnit on TestAll.
Bob feels ready to submit.
First, Bob jars everything up. He types
- cd topdir
jar -cvf a1-bob.jar cs414/a1/bob/*.java
topdir is the parent directory of cs414/a1/bob.
In case you want to try out the jar file just like a grader would do, you
can use the following example on the command line (departmental unix machines
or your own machine, assuming you have the Java commands installed).
Bob makes a new directory under topdir and copies the jar file there. There he tries an
unpack, compile, and run:
- mkdir a1-temp
cp a1-bob.jar a1-temp
cd a1-temp
jar -xvf a1-bob.jar
cd cs414/a1/bob
javac -classpath pathToJUnit/junit(yourversion).jar:. ../../../ *.java
etc.