运行 go test 后编译器会提示失败信息 ./dictionary_test.go:8:9: undefined: Search。
编写最少量的代码让测试运行并检查输出
在 dictionary.go 中:
package main
func Search(dictionary map[string]string, word string) string {
return ""
}
测试应该失败并显示明确的错误信息:
dictionary_test.go:12: got '' want 'this is just a test' given, 'test'。
编写足够的代码使测试通过
func Search(dictionary map[string]string, word string) string {
return dictionary[word]
}
从 map 中获取值和数组相同,都是通过 map[key] 的方式。
重构
func TestSearch(t *testing.T) {
dictionary := map[string]string{"test": "this is just a test"}
got := Search(dictionary, "test")
want := "this is just a test"
assertStrings(t, got, want)
}
func assertStrings(t *testing.T, got, want string) {
t.Helper()
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}
我决定创建一个 assertStrings 辅助函数并删除 given 的部分让实现更通用。
使用自定义的类型
我们可以通过为 map 创建新的类型并使用 Search 方法改进字典的使用。
在 dictionary_test.go 中:
func TestSearch(t *testing.T) {
dictionary := Dictionary{"test": "this is just a test"}
got := dictionary.Search("test")
want := "this is just a test"
assertStrings(t, got, want)
}
func TestSearch(t *testing.T) {
dictionary := Dictionary{"test": "this is just a test"}
t.Run("known word", func(t *testing.T) {
got, _ := dictionary.Search("test")
want := "this is just a test"
assertStrings(t, got, want)
})
t.Run("unknown word", func(t *testing.T) {
_, err := dictionary.Search("unknown")
want := "could not find the word you were looking for"
if err == nil {
t.Fatal("expected to get an error.")
}
assertStrings(t, err.Error(), want)
})
}
在 Go 中处理这种情况的方法是返回第二个参数,它是一个 Error 类型。
Error 类型可以使用 .Error() 方法转换为字符串,我们将其传递给断言时会执行此操作。我们也用 if 来保护 assertStrings,以确保我们不在 nil 上调用 .Error()。
尝试运行测试
这不会通过编译
./dictionary_test.go:18:10: assignment mismatch: 2 variables but 1 values
func (d Dictionary) Search(word string) (string, error) {
definition, ok := d[word]
if !ok {
return "", errors.New("could not find the word you were looking for")
}
return definition, nil
}
var ErrNotFound = errors.New("could not find the word you were looking for")
func (d Dictionary) Search(word string) (string, error) {
definition, ok := d[word]
if !ok {
return "", ErrNotFound
}
return definition, nil
}
./dictionary_test.go:30:13: dictionary.Add(word, definition) used as value
./dictionary_test.go:41:13: dictionary.Add(word, "new test") used as value
编写最少量的代码让测试运行并检查输出
在 dictionary.go 中:
var (
ErrNotFound = errors.New("could not find the word you were looking for")
ErrWordExists = errors.New("cannot add word because it already exists")
)
func (d Dictionary) Add(word, definition string) error {
d[word] = definition
return nil
}
现在我们又得到两个错误。我们仍在修改值,并返回 nil 错误。
dictionary_test.go:43: got error '%!s(<nil>)' want 'cannot add word because it already exists'
dictionary_test.go:44: got 'new test' want 'this is just a test'
const (
ErrNotFound = DictionaryErr("could not find the word you were looking for")
ErrWordExists = DictionaryErr("cannot add word because it already exists")
)
type DictionaryErr string
func (e DictionaryErr) Error() string {
return string(e)
}
我们将错误声明为常量,这需要我们创建自己的 DictionaryErr 类型来实现 error 接口。你可以在 Dave Cheney 的这篇优秀文章中了解更多相关的细节。简而言之,它使错误更具可重用性和不可变性。
首先编写测试
func TestUpdate(t *testing.T) {
word := "test"
definition := "this is just a test"
dictionary := Dictionary{word: definition}
newDefinition := "new definition"
dictionary.Update(word, newDefinition)
assertDefinition(t, dictionary, word, newDefinition)
}
Update 与 Create 密切相关,这是下一个需要我们实现的方法。
尝试运行测试
./dictionary_test.go:53:2: dictionary.Update undefined (type Dictionary has no field or method Update)
t.Run("existing word", func(t *testing.T) {
word := "test"
definition := "this is just a test"
newDefinition := "new definition"
dictionary := Dictionary{word: definition}
err := dictionary.Update(word, newDefinition)
assertError(t, err, nil)
assertDefinition(t, dictionary, word, newDefinition)
})
t.Run("new word", func(t *testing.T) {
word := "test"
definition := "this is just a test"
dictionary := Dictionary{}
err := dictionary.Update(word, definition)
assertError(t, err, ErrWordDoesNotExist)
})
我们在单词不存在时添加了另一种错误类型。我们还修改了 Update 以返回 error 值。
尝试运行测试
./dictionary_test.go:53:16: dictionary.Update(word, "new test") used as value
./dictionary_test.go:64:16: dictionary.Update(word, definition) used as value
./dictionary_test.go:66:23: undefined: ErrWordDoesNotExists
这次我们得到 3 个错误,但我们知道如何处理这些错误。
编写最少量的代码让测试运行并检查输出
const (
ErrNotFound = DictionaryErr("could not find the word you were looking for")
ErrWordExists = DictionaryErr("cannot add word because it already exists")
ErrWordDoesNotExist = DictionaryErr("cannot update word because it does not exist")
)
func (d Dictionary) Update(word, definition string) error {
d[word] = definition
return nil
}
我们添加了自己的错误类型并返回 nil 错误。
通过这些更改,我们现在得到一个非常明确的错误:
dictionary_test.go:66: got error '%!s(<nil>)' want 'cannot update word because it does not exist'