mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 03:34:19 +08:00
回到简体
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## 11.2. 測試函數
|
||||
## 11.2. 测试函数
|
||||
|
||||
每個測試函數必須導入testing包。測試函數有如下的籤名:
|
||||
每个测试函数必须导入testing包。测试函数有如下的签名:
|
||||
|
||||
```Go
|
||||
func TestName(t *testing.T) {
|
||||
@@ -8,7 +8,7 @@ func TestName(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
測試函數的名字必須以Test開頭,可選的後綴名必須以大寫字母開頭:
|
||||
测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头:
|
||||
|
||||
```Go
|
||||
func TestSin(t *testing.T) { /* ... */ }
|
||||
@@ -16,7 +16,7 @@ func TestCos(t *testing.T) { /* ... */ }
|
||||
func TestLog(t *testing.T) { /* ... */ }
|
||||
```
|
||||
|
||||
其中t參數用於報告測試失敗和附加的日誌信息。讓我們定義一個實例包gopl.io/ch11/word1,其中隻有一個函數IsPalindrome用於檢査一個字符串是否從前向後和從後向前讀都是一樣的。(下面這個實現對於一個字符串是否是迴文字符串前後重複測試了兩次;我們稍後會再討論這個問題。)
|
||||
其中t参数用于报告测试失败和附加的日志信息。让我们定义一个实例包gopl.io/ch11/word1,其中只有一个函数IsPalindrome用于检查一个字符串是否从前向后和从后向前读都是一样的。(下面这个实现对于一个字符串是否是回文字符串前后重复测试了两次;我们稍后会再讨论这个问题。)
|
||||
|
||||
<u><i>gopl.io/ch11/word1</i></u>
|
||||
```Go
|
||||
@@ -35,7 +35,7 @@ func IsPalindrome(s string) bool {
|
||||
}
|
||||
```
|
||||
|
||||
在相同的目録下,word_test.go測試文件中包含了TestPalindrome和TestNonPalindrome兩個測試函數。每一個都是測試IsPalindrome是否給出正確的結果,併使用t.Error報告失敗信息:
|
||||
在相同的目录下,word_test.go测试文件中包含了TestPalindrome和TestNonPalindrome两个测试函数。每一个都是测试IsPalindrome是否给出正确的结果,并使用t.Error报告失败信息:
|
||||
|
||||
```Go
|
||||
package word
|
||||
@@ -58,7 +58,7 @@ func TestNonPalindrome(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
`go test`命令如果沒有參數指定包那麽將默認采用當前目録對應的包(和`go build`命令一樣)。我們可以用下面的命令構建和運行測試。
|
||||
`go test`命令如果没有参数指定包那么将默认采用当前目录对应的包(和`go build`命令一样)。我们可以用下面的命令构建和运行测试。
|
||||
|
||||
```
|
||||
$ cd $GOPATH/src/gopl.io/ch11/word1
|
||||
@@ -66,7 +66,7 @@ $ go test
|
||||
ok gopl.io/ch11/word1 0.008s
|
||||
```
|
||||
|
||||
結果還比較滿意,我們運行了這個程序, 不過沒有提前退出是因爲還沒有遇到BUG報告。不過一個法国名爲“Noelle Eve Elleon”的用戶會抱怨IsPalindrome函數不能識别“été”。另外一個來自美国中部用戶的抱怨則是不能識别“A man, a plan, a canal: Panama.”。執行特殊和小的BUG報告爲我們提供了新的更自然的測試用例。
|
||||
结果还比较满意,我们运行了这个程序, 不过没有提前退出是因为还没有遇到BUG报告。不过一个法国名为“Noelle Eve Elleon”的用户会抱怨IsPalindrome函数不能识别“été”。另外一个来自美国中部用户的抱怨则是不能识别“A man, a plan, a canal: Panama.”。执行特殊和小的BUG报告为我们提供了新的更自然的测试用例。
|
||||
|
||||
```Go
|
||||
func TestFrenchPalindrome(t *testing.T) {
|
||||
@@ -83,9 +83,9 @@ func TestCanalPalindrome(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
爲了避免兩次輸入較長的字符串,我們使用了提供了有類似Printf格式化功能的 Errorf函數來滙報錯誤結果。
|
||||
为了避免两次输入较长的字符串,我们使用了提供了有类似Printf格式化功能的 Errorf函数来汇报错误结果。
|
||||
|
||||
當添加了這兩個測試用例之後,`go test`返迴了測試失敗的信息。
|
||||
当添加了这两个测试用例之后,`go test`返回了测试失败的信息。
|
||||
|
||||
```
|
||||
$ go test
|
||||
@@ -97,11 +97,11 @@ FAIL
|
||||
FAIL gopl.io/ch11/word1 0.014s
|
||||
```
|
||||
|
||||
先編寫測試用例併觀察到測試用例觸發了和用戶報告的錯誤相同的描述是一個好的測試習慣。隻有這樣,我們才能定位我們要眞正解決的問題。
|
||||
先编写测试用例并观察到测试用例触发了和用户报告的错误相同的描述是一个好的测试习惯。只有这样,我们才能定位我们要真正解决的问题。
|
||||
|
||||
先寫測試用例的另外的好處是,運行測試通常會比手工描述報告的處理更快,這讓我們可以進行快速地迭代。如果測試集有很多運行緩慢的測試,我們可以通過隻選擇運行某些特定的測試來加快測試速度。
|
||||
先写测试用例的另外的好处是,运行测试通常会比手工描述报告的处理更快,这让我们可以进行快速地迭代。如果测试集有很多运行缓慢的测试,我们可以通过只选择运行某些特定的测试来加快测试速度。
|
||||
|
||||
參數`-v`可用於打印每個測試函數的名字和運行時間:
|
||||
参数`-v`可用于打印每个测试函数的名字和运行时间:
|
||||
|
||||
```
|
||||
$ go test -v
|
||||
@@ -120,7 +120,7 @@ exit status 1
|
||||
FAIL gopl.io/ch11/word1 0.017s
|
||||
```
|
||||
|
||||
參數`-run`對應一個正則表達式,隻有測試函數名被它正確匹配的測試函數才會被`go test`測試命令運行:
|
||||
参数`-run`对应一个正则表达式,只有测试函数名被它正确匹配的测试函数才会被`go test`测试命令运行:
|
||||
|
||||
```
|
||||
$ go test -v -run="French|Canal"
|
||||
@@ -135,11 +135,11 @@ exit status 1
|
||||
FAIL gopl.io/ch11/word1 0.014s
|
||||
```
|
||||
|
||||
當然,一旦我們已經脩複了失敗的測試用例,在我們提交代碼更新之前,我們應該以不帶參數的`go test`命令運行全部的測試用例,以確保脩複失敗測試的同時沒有引入新的問題。
|
||||
当然,一旦我们已经修复了失败的测试用例,在我们提交代码更新之前,我们应该以不带参数的`go test`命令运行全部的测试用例,以确保修复失败测试的同时没有引入新的问题。
|
||||
|
||||
我們現在的任務就是脩複這些錯誤。簡要分析後發現第一個BUG的原因是我們采用了 byte而不是rune序列,所以像“été”中的é等非ASCII字符不能正確處理。第二個BUG是因爲沒有忽略空格和字母的大小寫導致的。
|
||||
我们现在的任务就是修复这些错误。简要分析后发现第一个BUG的原因是我们采用了 byte而不是rune序列,所以像“été”中的é等非ASCII字符不能正确处理。第二个BUG是因为没有忽略空格和字母的大小写导致的。
|
||||
|
||||
針對上述兩個BUG,我們仔細重寫了函數:
|
||||
针对上述两个BUG,我们仔细重写了函数:
|
||||
|
||||
<u><i>gopl.io/ch11/word2</i></u>
|
||||
```Go
|
||||
@@ -166,7 +166,7 @@ func IsPalindrome(s string) bool {
|
||||
}
|
||||
```
|
||||
|
||||
同時我們也將之前的所有測試數據合併到了一個測試中的表格中。
|
||||
同时我们也将之前的所有测试数据合并到了一个测试中的表格中。
|
||||
|
||||
```Go
|
||||
func TestIsPalindrome(t *testing.T) {
|
||||
@@ -196,24 +196,24 @@ func TestIsPalindrome(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
現在我們的新測試阿都通過了:
|
||||
现在我们的新测试阿都通过了:
|
||||
|
||||
```
|
||||
$ go test gopl.io/ch11/word2
|
||||
ok gopl.io/ch11/word2 0.015s
|
||||
```
|
||||
|
||||
這種表格驅動的測試在Go語言中很常見的。我們很容易向表格添加新的測試數據,併且後面的測試邏輯也沒有冗餘,這樣我們可以有更多的精力地完善錯誤信息。
|
||||
这种表格驱动的测试在Go语言中很常见的。我们很容易向表格添加新的测试数据,并且后面的测试逻辑也没有冗余,这样我们可以有更多的精力地完善错误信息。
|
||||
|
||||
失敗測試的輸出併不包括調用t.Errorf時刻的堆棧調用信息。和其他編程語言或測試框架的assert斷言不同,t.Errorf調用也沒有引起panic異常或停止測試的執行。卽使表格中前面的數據導致了測試的失敗,表格後面的測試數據依然會運行測試,因此在一個測試中我們可能了解多個失敗的信息。
|
||||
失败测试的输出并不包括调用t.Errorf时刻的堆栈调用信息。和其他编程语言或测试框架的assert断言不同,t.Errorf调用也没有引起panic异常或停止测试的执行。即使表格中前面的数据导致了测试的失败,表格后面的测试数据依然会运行测试,因此在一个测试中我们可能了解多个失败的信息。
|
||||
|
||||
如果我們眞的需要停止測試,或許是因爲初始化失敗或可能是早先的錯誤導致了後續錯誤等原因,我們可以使用t.Fatal或t.Fatalf停止當前測試函數。它們必須在和測試函數同一個goroutine內調用。
|
||||
如果我们真的需要停止测试,或许是因为初始化失败或可能是早先的错误导致了后续错误等原因,我们可以使用t.Fatal或t.Fatalf停止当前测试函数。它们必须在和测试函数同一个goroutine内调用。
|
||||
|
||||
測試失敗的信息一般的形式是“f(x) = y, want z”,其中f(x)解釋了失敗的操作和對應的輸出,y是實際的運行結果,z是期望的正確的結果。就像前面檢査迴文字符串的例子,實際的函數用於f(x)部分。如果顯示x是表格驅動型測試中比較重要的部分,因爲同一個斷言可能對應不同的表格項執行多次。要避免無用和冗餘的信息。在測試類似IsPalindrome返迴布爾類型的函數時,可以忽略併沒有額外信息的z部分。如果x、y或z是y的長度,輸出一個相關部分的簡明總結卽可。測試的作者應該要努力幫助程序員診斷測試失敗的原因。
|
||||
测试失败的信息一般的形式是“f(x) = y, want z”,其中f(x)解释了失败的操作和对应的输出,y是实际的运行结果,z是期望的正确的结果。就像前面检查回文字符串的例子,实际的函数用于f(x)部分。如果显示x是表格驱动型测试中比较重要的部分,因为同一个断言可能对应不同的表格项执行多次。要避免无用和冗余的信息。在测试类似IsPalindrome返回布尔类型的函数时,可以忽略并没有额外信息的z部分。如果x、y或z是y的长度,输出一个相关部分的简明总结即可。测试的作者应该要努力帮助程序员诊断测试失败的原因。
|
||||
|
||||
**練習 11.1:** 爲4.3節中的charcount程序編寫測試。
|
||||
**练习 11.1:** 为4.3节中的charcount程序编写测试。
|
||||
|
||||
**練習 11.2:** 爲(§6.5)的IntSet編寫一組測試,用於檢査每個操作後的行爲和基於內置map的集合等價,後面練習11.7將會用到。
|
||||
**练习 11.2:** 为(§6.5)的IntSet编写一组测试,用于检查每个操作后的行为和基于内置map的集合等价,后面练习11.7将会用到。
|
||||
|
||||
|
||||
{% include "./ch11-02-1.md" %}
|
||||
|
||||
Reference in New Issue
Block a user