// Package word provides utilities for word games.packageword// IsPalindrome reports whether s reads the same forward and backward.// (Our first attempt.)funcIsPalindrome(s string) bool {for i :=range s {if s[i] != s[len(s)-1-i] {returnfalse } }returntrue}
go test命令如果没有参数指定包那么将默认采用当前目录对应的包(和go build命令一样)。我们可以用下面的命令构建和运行测试。
$ cd $GOPATH/src/gopl.io/ch11/word1
$ go test
ok gopl.io/ch11/word1 0.008s
结果还比较满意,我们运行了这个程序, 不过没有提前退出是因为还没有遇到BUG报告。不过一个法国名为“Noelle Eve Elleon”的用户会抱怨IsPalindrome函数不能识别“été”。另外一个来自美国中部用户的抱怨则是不能识别“A man, a plan, a canal: Panama.”。执行特殊和小的BUG报告为我们提供了新的更自然的测试用例。
// Package word provides utilities for word games.packagewordimport"unicode"// IsPalindrome reports whether s reads the same forward and backward.// Letter case is ignored, as are non-letters.funcIsPalindrome(s string) bool {var letters []runefor _, r :=range s {if unicode.IsLetter(r) { letters =append(letters, unicode.ToLower(r)) } }for i :=range letters {if letters[i] != letters[len(letters)-1-i] {returnfalse } }returntrue}
同时我们也将之前的所有测试数据合并到了一个测试中的表格中。
funcTestIsPalindrome(t *testing.T) {var tests = []struct { input string want bool }{ {"", true}, {"a", true}, {"aa", true}, {"ab", false}, {"kayak", true}, {"detartrated", true}, {"A man, a plan, a canal: Panama", true}, {"Evil I did dwell; lewd did I live.", true}, {"Able was I ere I saw Elba", true}, {"été", true}, {"Et se resservir, ivresse reste.", true}, {"palindrome", false}, // non-palindrome {"desserts", false}, // semi-palindrome }for _, test :=range tests {if got :=IsPalindrome(test.input); got != test.want { t.Errorf("IsPalindrome(%q) = %v", test.input, got) } }}
现在我们的新测试阿都通过了:
$ go test gopl.io/ch11/word2
ok gopl.io/ch11/word2 0.015s
测试失败的信息一般的形式是“f(x) = y, want z”,其中f(x)解释了失败的操作和对应的输出,y是实际的运行结果,z是期望的正确的结果。就像前面检查回文字符串的例子,实际的函数用于f(x)部分。如果显示x是表格驱动型测试中比较重要的部分,因为同一个断言可能对应不同的表格项执行多次。要避免无用和冗余的信息。在测试类似IsPalindrome返回布尔类型的函数时,可以忽略并没有额外信息的z部分。如果x、y或z是y的长度,输出一个相关部分的简明总结即可。测试的作者应该要努力帮助程序员诊断测试失败的原因。