I’m trying to get a deeper understanding of Go by implementing tests locally, and I’m having difficulty understanding task 3 - Drive the car, of the Need For Speed exercise.
The specification and example for this task are:
Implement the Drive
function that updates the number of meters driven based on the car’s speed, and reduces the battery according to the battery drainage. If there is not enough battery to drive one more time the car will not move:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car = Drive(car)
// => Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
When a new car is created (by calling NewCar
method), the default battery is always 100 and the default distance is always 0.
The test function for this task calls Drive
directly without calling NewCar
. In doing so, a custom Car object with non-default values for battery and distance are passed to the Drive
function.
So my question is:
-
Is car := NewCar(speed, batteryDrain)
incorrect and should not be a part of the example ?
-
Or is the test incorrect because it calls Drive
directly without calling NewCar()
?
In my opinion it’s a neither nor.
The test is for testing Drive
without additional dependencies and with pre-defined situations of a Car
. Is not necessarily a new car. It want to test how Drive
will behave for certain Car
s.
On the other hand, when using in your code you would start with a New...
function for initialization.
The test is for testing Drive
without additional dependencies and with pre-defined situations of a Car
. Is not necessarily a new car. It want to test how Drive
will behave for certain Car
s.
If this is the case, why is the task description:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car.Drive()
// car is now Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
instead of:
speed := 5
batteryDrain := 2
car := Car{speed: 5, batterDrain: 2}
car.Drive()
// car is now Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
?
As I said: You usually offer Initializers or constructors for your types, so they are used correctly. It’s still only a convention, unless your internals aren’t exported.
But tests go often deeper into your structure and define the states raw and directly, to simulate preconditions. The NewCar
itself is tested, too.
The test is not a blueprint for how to use your type.
I understand initializers, constructors, and convention. What you’re saying is contradictory to the task specification:
The test is for testing Drive
without additional dependencies and with pre-defined situations of a Car
.
Why not remove car := NewCar(speed, batteryDrain)
from the task’s code block and create a custom car object with example values for speed, distance, battery, and battery drain?
Is not necessarily a new car. It want to test how Drive
will behave for certain Car
s.
Again, why is this stated in the task description is the form of car := NewCar(speed, batteryDrain)
?