One reason I don't use BDD on the regular is that the devil is in the details, and BDD hides detail rather than exposing it. For example, your last line is
Then its new position should be the sum of its old position and its velocity.
I'm instantly confused:
- Are the boids moving in one-, two-, three-, or some higher-dimensional space? Or is the code meant to handle any positive number of dimensions?
- Does adding position and velocity make sense? In physics, position is defined in terms of metres, and velocity is defined using metres per second, so they can't be added as physical properties. Which leads to the next confusion:
- What about the time step? If you're trying to simulate boids live your calculation needs to take into account how long it's been since the last move. You wouldn't want the boids to behave differently when viewed with different refresh rates, or on different CPUs.
There is a more fundamental problem with your test code, if I read it correctly. Compare with the following test:
old_position = (1, 2, 3)
velocity = (0, 1, 2)
new_position = (1, 3, 5) # This is key!
boid = Boid(old_position, velocity)
boid.move()
assert_equal(new_position, boid.position)
Now, instead of repeating the calculation from your production code in the test, we're actually checking that the calculation does the right thing, and that the thing it does is easily verifiable. Verifying that + does the same thing in your test and the production code is pointless, but verifying that + in fact adds up the relevant parts of the vector is quite useful - it could've just been adding entries to a tuple!
You could also use random values for the inputs, to verify (over subsequent runs) that it handles many different values properly. In this case you have to duplicate at least part of the production code to verify the result:
old_position = (random_number(), random_number(), random_number())
velocity = (random_number(), random_number(), random_number())
new_position = (
old_position[0] + velocity[0],
old_position[1] + velocity[1],
old_position[2] + velocity[2],
)
boid = Boid(old_position, velocity)
boid.move()
assert_equal(new_position, boid.position)
In addition to these issues, there's the very real possibility that your position and/or velocity might be floating point numbers, in which case you probably want some assert_almost_equal variant for most of your assertions.