Lab 12a
Lab 12a Description
The goal of this lab is to think about the design of tests in the presence of mutation and explore how the design and testing of an interactive game changes when converted to the imperative style.
Game change
The library javalib.impworld.jar supports the design of the interactive games using imperative style (mutation). The methods onTick, onKeyEvent, OnMouseClisk(Posn p), (and all other mouse handling methods) have the return type void. Each method causes the state of the game to be modified to reflect the desired changes.
The tests for the methods with effects are more difficult. We need to make sure the data we use is set up as desired, invoke the method whose effects we want to test, then run the tests (and possibly, clean up after the test).
The starter files:
The file that contains the images of the shark and the fish used in our game Images.zip.
The complete game written in the functional style ExamplesOceanWorldFun.java.
Start a new project, import the solution in the functional style, as well as all the needed images. Add to the classpath the libraries: javalib.jar and tester.jar.
Change the import in the solution from import javalib.funworld.*; to import javalib.impworld.*;
Comment out the tests for all methods except for the class Fish and the class CartPt. Also comment out all class definitions except the interface WorldConstants, class Fish, and class CartPt. Now change the methods in these classes to the imperative style, and modify the tests.
Here is an example:
// In the class Fish:
// EFFECT:
// move the fish to the right side of the ocean
// and reset its size
void start(int y, int size){
this.p.x = WIDTH;
this.p.y = y;
this.size = size;
}
// in the class ExamplesOceanWorldImp:
// test all methods in the class Fish
public void testFishMethods(Tester t){
this.f.start(30, 50);
t.checkExpect(this.f, new Fish(new CartPt(WIDTH, 30), 50, this.f.name));
}
Make sure all test cases pass.
Do the same for the class Shark.
Continue with the other classes. Notice, that to make some tests pass, you need to reset the data. To make this easier, our appreoach is to design one or more #tt{reset} methods that just reproduce the original initialization of all data, and invoke this method before each test that may need it.
The solution ExamplesOceanWorldImp.java shows you this technique. Please, note the comments in the method moveLeftRandom in the class CartPt:
//EFFECT:
// Move this CartPt left i units -- or back to the right, if out of bounds
// also move randomly up or down -2 to 2 pixel
void moveLeftRandom(int i) {
if (this.x - i < 0)
this.x = WIDTH;
else{
// our tests did not catch that rand.nextInt(2) did not provide all desired values
this.x = this.x-i;
this.y = this.y + rand.nextInt(5) - 2;
}
// NOTE: My tests found the error in this simple method: I forgot to enclose the
// two statements in the else clause in brackets, and so, the y coordinate
// was changing regardless of whether the fish moved back to the start!!!
}