Before the lab
Background
This lab is based on Chapter 7 of the Eloquent JavaScript.
You will also need ES2015 classes, which were discussed in L11
Discussion
- Time
- 10 minutes
- Questions on Assignment 3
- Questions on the Quiz 2
- Questions on Lab 11
Completing test coverage for VillageState
- Time
- 20 minutes
- Activity
- individual
Copy your files from the second half of L11 (or use my village.js and village.spec.js.
Observe that the two tests we added for
VillageState
in L11 do not result in complete test coverage (runnyc jasmine
to check).Read the explanation of
move
in the book.Add a test of a move to an invalid destination, and a test that adds a parcel that is not carried by the robot.
The strategy of basing your tests on knowledge of the code being tested is called called "white box testing", as opposed to "black box testing".
Testing the random robot I/II
- Time
- 20 minutes
- Activity
- individual, adding tests
The function runRobot provides several challenges to our usual unit testing methodology. The first is the we need to test it's output (i.e. from console.log) rather than it's return value.
copy the source for
runRobot
from Eloquent JavaScript intovillage.js
(note thatrunRobot
is not a method of VillageState).We can use a spy to intercept calls to
console.log
. Fill in the missing parts for this test suite.
describe("runRobot",
function() {
it("no parcels",
function() {
console.log = _________________________;
noParcels = new VillageState("Post Office",[]);
village.runRobot(noParcels);
expect(console.log).toHaveBeenCalledWith(________________);
})});
Testing the random robot II/II
- Time
- 25 minutes
- Activity
- Demo / individual
Of course delivering no parcels does not offer us complete code coverage. The second unit testing challenge becomes apparent, that top down coding does not really work for unit testing: we can't really test runRobot without some more functions. One solution is more use of spies, but let's simplify our life and just copy the code for
VillageState.random
,randomPick
andrandomRobot
intovillage.js
.As explained in the book, we can now call
runRobot(VillageState.random(), randomRobot);
or, from the book in the browser
runRobotAnimation(VillageState.random(), randomRobot);
After watching the pretty animation, let's figure out how to test the random robot. One annoying problem is that the output is different every time. Use jasmine.stringMatching or the toMatch matcher to make a modified version of the previous
runRobot
test that passes when console.log is called with a starting with "Done".You should have 100% test coverage after adding this one test.
Robot with a route
- Time
- 25 minutes
- Activity
- Individual, following book
Add routeRobot to
village.js
(and export it).- For your journal: what racket idiom is this recursion similar to?
Add another test by copying your last test, and using the follow code to test the new robot:
village.runRobot(village.VillageState.random(), village.routeRobot, []);
- Similarly this test yields 100% test coverage for the new robot. On
the other hand, it's not very satisfactory that our testing doesn't
really distinguish the two robots. The
book
suggests writing a function
compareRobots
which measures the average number of steps. This kind of measurement is tough to do in a unit test, so let's take a break fromjasmine
and write the functioncompareRobots
. Create a new filecompareRobot.js
that imports thevillage.js
module.
let village=require("./village.js");
function measureRobot(state, robot, memory) {
for (let turn = 0;; turn++) {
if (state.parcels.length == 0) {
return turn;
}
let action = robot(state, memory);
state = state.move(action.direction);
memory = action.memory;
}
}
function compareRobots(robot1, memory1, robot2, memory2) {
// your code goes here
}
compareRobots(village.routeRobot,[], village.randomRobot, []);
- It's tempting to write a test that the average number of turns for the routeRobot is always less than that for the random robot. Explain in your journal why this test could fail.