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.