Countdownwhich we will then put inside a
mainprogram so it looks something like this:
Countdownfunction to write data somewhere and
io.Writeris the de-facto way of capturing that as an interface in Go.
mainwe will send to
os.Stdoutso our users see the countdown printed to the terminal.
bytes.Bufferso our tests can capture what data is being generated.
./countdown_test.go:11:2: undefined: Countdown
countdown_test.go:17: got '' want '3'
fmt.Fprintwhich takes an
*bytes.Buffer) and sends a
stringto it. The test should pass.
*bytes.Bufferworks, it would be better to use a general purpose interface instead.
mainso we have some working software to reassure ourselves we're making progress.
stringbut lets you put things like newlines which is perfect for our test.
forloop counting backwards with
fmt.Fprintlnto print to
outwith our number followed by a newline character. Finally use
fmt.Fprintto send "Go!" aftward.
time.Sleep. Try adding it in to our code.
Sleeping which we need to extract so we can then control it in our tests.
time.Sleepwe can use dependency injection to use it instead of a "real"
time.Sleepand then we can spy on the calls to make assertions on them.
mainand a spy sleeper in our tests. By using an interface our
Countdownfunction is oblivious to this and adds some flexibility for the caller.
Countdownfunction would not be responsible for how long the sleep is. This simplifies our code a little for now at least and means a user of our function can configure that sleepiness however they like.
Sleep()is called so we can check it in our test.
Countdownto accept our
mainwill no longer compile for the same reason
time.Sleeprather than the injected in dependency. Let's fix that.
Countdownshould sleep before each print, e.g:
Sleeper, recording every call into one slice. In this test we're only concerned about the order of operations, so just recording them as list of named operations is sufficient.
Countdownback to how it was to fix the test.
Sleeperso we can now refactor our test so one is testing what is being printed and the other one is ensuring we're sleeping in between the prints. Finally we can delete our first spy as it's not used anymore.
Sleeperto be configurable. This means that we can adjust the sleep time in our main program.
ConfigurableSleeperthat accepts what we need for configuration and testing.
durationto configure the time slept and
sleepas a way to pass in a sleep function. The signature of
sleepis the same as for
time.Sleepallowing us to use
time.Sleepin our real implementation and the following spy in our tests:
Sleepmethod created on our
Sleepfunction implemented we have a failing test.
ConfigurableSleeperin the main function.
"When to use iterative development? You should use iterative development only on projects that you want to succeed."