bytes.Buffer
尝试并运行测试
./countdown_test.go:11:2: undefined: Countdown
为测试的运行编写最少量的代码,并检查失败测试的输出
Countdown
func Countdown() {}
再次尝试运行
./countdown_test.go:11:11: too many arguments in call to Countdown
have (*bytes.Buffer)
want ()
编译器正在告诉你函数的问题,所以更正它
func Countdown(out *bytes.Buffer) {}
countdown_test.go:17: got '' want '3'
这样结果就完美了!
编写足够的代码使程序通过
func Countdown(out *bytes.Buffer) {
fmt.Fprint(out, "3")
}
fmt.Fprintio.Writer*bytes.Bufferstring
重构代码
*bytes.Buffer
func Countdown(out io.Writer) {
fmt.Fprint(out, "3")
}
重新运行测试他们应该就可以通过了。
package main
import (
"fmt"
"io"
"os"
)
func Countdown(out io.Writer) {
fmt.Fprint(out, "3")
}
func main() {
Countdown(os.Stdout)
}
func TestCountdown(t *testing.T) {
buffer := &bytes.Buffer{}
Countdown(buffer)
got := buffer.String()
want := `3
2
1
Go!`
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}
func Countdown(out io.Writer) {
for i := 3; i > 0; i-- {
fmt.Fprintln(out, i)
}
fmt.Fprint(out, "Go!")
}
const finalWord = "Go!"
const countdownStart = 3
func Countdown(out io.Writer) {
for i := countdownStart; i > 0; i-- {
fmt.Fprintln(out, i)
}
fmt.Fprint(out, finalWord)
}
func Countdown(out io.Writer) {
for i := countdownStart; i > 0; i-- {
time.Sleep(1 * time.Second)
fmt.Fprintln(out, i)
}
time.Sleep(1 * time.Second)
fmt.Fprint(out, finalWord)
}
type Sleeper interface {
Sleep()
}
type SpySleeper struct {
Calls int
}
func (s *SpySleeper) Sleep() {
s.Calls++
}
func TestCountdown(t *testing.T) {
buffer := &bytes.Buffer{}
spySleeper := &SpySleeper{}
Countdown(buffer, spySleeper)
got := buffer.String()
want := `3
2
1
Go!`
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
if spySleeper.Calls != 4 {
t.Errorf("not enough calls to sleeper, want 4 got %d", spySleeper.Calls)
}
}
func Countdown(out io.Writer, sleeper Sleeper) {
for i := countdownStart; i > 0; i-- {
time.Sleep(1 * time.Second)
fmt.Fprintln(out, i)
}
time.Sleep(1 * time.Second)
fmt.Fprint(out, finalWord)
}
type ConfigurableSleeper struct {
duration time.Duration
}
func (o *ConfigurableSleeper) Sleep() {
time.Sleep(o.duration)
}
func main() {
sleeper := &ConfigurableSleeper{1 * time.Second}
Countdown(os.Stdout, sleeper)
}
func Countdown(out io.Writer, sleeper Sleeper) {
for i := countdownStart; i > 0; i-- {
sleeper.Sleep()
fmt.Fprintln(out, i)
}
sleeper.Sleep()
fmt.Fprint(out, finalWord)
}
func Countdown(out io.Writer, sleeper Sleeper) {
for i := countdownStart; i > 0; i-- {
sleeper.Sleep()
}
for i := countdownStart; i > 0; i-- {
fmt.Fprintln(out, i)
}
sleeper.Sleep()
fmt.Fprint(out, finalWord)
}
type CountdownOperationsSpy struct {
Calls []string
}
func (s *CountdownOperationsSpy) Sleep() {
s.Calls = append(s.Calls, sleep)
}
func (s *CountdownOperationsSpy) Write(p []byte) (n int, err error) {
s.Calls = append(s.Calls, write)
return
}
const write = "write"
const sleep = "sleep"
t.Run("sleep after every print", func(t *testing.T) {
spySleepPrinter := &CountdownOperationsSpy{}
Countdown(spySleepPrinter, spySleepPrinter)
want := []string{
sleep,
write,
sleep,
write,
sleep,
write,
sleep,
write,
}
if !reflect.DeepEqual(want, spySleepPrinter.Calls) {
t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls)
}
})
func TestCountdown(t *testing.T) {
t.Run("prints 3 to Go!", func(t *testing.T) {
buffer := &bytes.Buffer{}
Countdown(buffer, &CountdownOperationsSpy{})
got := buffer.String()
want := `3
2
1
Go!`
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
})
t.Run("sleep after every print", func(t *testing.T) {
spySleepPrinter := &CountdownOperationsSpy{}
Countdown(spySleepPrinter, spySleepPrinter)
want := []string{
sleep,
write,
sleep,
write,
sleep,
write,
sleep,
write,
}
if !reflect.DeepEqual(want, spySleepPrinter.Calls) {
t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls)
}
})
}