Comet wants to add a B command that turns Pip all the way around. "Two right turns," she says. "Easy. Let's add it now."
Wren holds up a page of assert lines. "What does the evidence say after you add it?" he asks. "If every old test still passes, we know nothing else broke."
Nova projects a folder icon splitting into two. "How can I help?" she asks. "Try the new idea in a copy of the folder. Keep the real one safe."
"Deal," Comet says. "Lead programmer, the tests come first. Then my B."
Testing and refining is a deliberate, repeated process: debugging, and comparing what a program does with what it should do.
Each test function below sets up a small case and checks it with assert. The tests aim at the edges: a corner, a rock, off the field.
# test_fieldsim.py
# Tests for FieldSim. Run this file: it prints one line when all pass.
from field_data import FIELD
from grid import FieldGrid
from rover import Rover
from sample import Sample
def test_grid():
grid = FieldGrid(FIELD)
assert grid.height() == 5
assert grid.width() == 6
assert grid.is_open(0, 0)
assert not grid.is_open(1, 1)
assert not grid.is_open(-1, 0)
assert not grid.is_open(0, 6)
def test_turns():
rover = Rover("Test")
rover.turn_right()
assert rover.get_heading() == "S"
rover.turn_left()
rover.turn_left()
assert rover.get_heading() == "N"
def test_move():
grid = FieldGrid(FIELD)
rover = Rover("Test")
assert rover.move(grid)
assert (rover.get_row(), rover.get_col()) == (0, 1)
assert rover.get_battery() == 95
rover.turn_left()
assert not rover.move(grid)
assert rover.get_row() == 0
def test_pick_up():
rover = Rover("Test")
for n in range(3):
assert rover.pick_up(Sample(f"T{n}", "clay", 10))
assert not rover.pick_up(Sample("T3", "clay", 10))
assert rover.total_grams() == 30
test_grid()
test_turns()
test_move()
test_pick_up()
print("All FieldSim tests passed") All FieldSim tests passed
| Test | Edge case it checks |
|---|---|
| test_grid | the corner (0, 0) is open; a rock; row -1 and column 6 are off the field |
| test_turns | turning right then left twice gives the right headings |
| test_move | one open step uses 5 battery; a step off the top edge is refused |
| test_pick_up | three samples fit and the fourth does not |
A test that fails: here test_move expects battery 90 instead of 95. The run compares what happened with what the test said should happen:
Traceback (most recent call last):
File "test_fieldsim.py", line 49, in <module>
test_move()
~~~~~~~~~^^
File "test_fieldsim.py", line 33, in test_move
assert rover.get_battery() == 90
^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError An edge case: exactly enough battery. System reliability means a program does its job as expected without failing. Programmers test with many conditions to improve it, including the limits.
# test_battery.py
# Edge case: the battery has exactly enough for one more step.
from grid import FieldGrid
from rover import Rover
def test_battery_edge():
grid = FieldGrid(["." * 22])
rover = Rover("Test")
for n in range(20):
assert rover.move(grid)
assert rover.get_battery() == 0
assert not rover.move(grid)
assert rover.get_log()[-1] == "battery low"
test_battery_edge()
print("Battery edge test passed") Comet's B command goes into a copy of the whole folder, fieldsim_try. In the copy, run() gets one more branch, and the tests get test_back:
def run(self, commands, grid):
"""Follow a command string: F forward, L left, R right."""
for c in commands:
if c == "F":
self.move(grid)
elif c == "L":
self.turn_left()
elif c == "R":
self.turn_right()
elif c == "B":
self.turn_right()
self.turn_right()
else:
self._log.append(f"unknown command {c}") def test_back():
rover = Rover("Test")
rover.run("B", FieldGrid(FIELD))
assert rover.get_heading() == "W" In fieldsim_try, test_fieldsim.py also calls test_back() just before the last print. The run:
All FieldSim tests passed
| Statement | True or false? |
|---|---|
| After adding B, all the old tests still pass. | ? |
| Rerunning old tests after a change can catch something that broke. | ? |
| The B command is added to the real rover.py in fieldsim. | ? |
| An edge case tests a limit, like exactly enough battery. | ? |
Your rover drives and your tests guard it. Tomorrow is a Mission Quest with a coin and the paper field.