mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-08 08:12:02 +00:00
回到简体
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
### 11.2.5. 編寫有效的測試
|
||||
### 11.2.5. 编写有效的测试
|
||||
|
||||
許多Go語言新人會驚異於它的極簡的測試框架。很多其它語言的測試框架都提供了識别測試函數的機製(通常使用反射或元數據),通過設置一些“setup”和“teardown”的鉤子函數來執行測試用例運行的初始化和之後的清理操作,同時測試工具箱還提供了很多類似assert斷言,值比較函數,格式化輸出錯誤信息和停止一個識别的測試等輔助函數(通常使用異常機製)。雖然這些機製可以使得測試非常簡潔,但是測試輸出的日誌卻會像火星文一般難以理解。此外,雖然測試最終也會輸出PASS或FAIL的報告,但是它們提供的信息格式卻非常不利於代碼維護者快速定位問題,因爲失敗的信息的具體含義是非常隱晦的,比如“assert: 0 == 1”或成頁的海量跟蹤日誌。
|
||||
许多Go语言新人会惊异于它的极简的测试框架。很多其它语言的测试框架都提供了识别测试函数的机制(通常使用反射或元数据),通过设置一些“setup”和“teardown”的钩子函数来执行测试用例运行的初始化和之后的清理操作,同时测试工具箱还提供了很多类似assert断言,值比较函数,格式化输出错误信息和停止一个识别的测试等辅助函数(通常使用异常机制)。虽然这些机制可以使得测试非常简洁,但是测试输出的日志却会像火星文一般难以理解。此外,虽然测试最终也会输出PASS或FAIL的报告,但是它们提供的信息格式却非常不利于代码维护者快速定位问题,因为失败的信息的具体含义是非常隐晦的,比如“assert: 0 == 1”或成页的海量跟踪日志。
|
||||
|
||||
Go語言的測試風格則形成鮮明對比。它期望測試者自己完成大部分的工作,定義函數避免重複,就像普通編程那樣。編寫測試併不是一個機械的填空過程;一個測試也有自己的接口,盡管它的維護者也是測試僅有的一個用戶。一個好的測試不應該引發其他無關的錯誤信息,它隻要清晰簡潔地描述問題的癥狀卽可,有時候可能還需要一些上下文信息。在理想情況下,維護者可以在不看代碼的情況下就能根據錯誤信息定位錯誤産生的原因。一個好的測試不應該在遇到一點小錯誤時就立刻退出測試,它應該嚐試報告更多的相關的錯誤信息,因爲我們可能從多個失敗測試的模式中發現錯誤産生的規律。
|
||||
Go语言的测试风格则形成鲜明对比。它期望测试者自己完成大部分的工作,定义函数避免重复,就像普通编程那样。编写测试并不是一个机械的填空过程;一个测试也有自己的接口,尽管它的维护者也是测试仅有的一个用户。一个好的测试不应该引发其他无关的错误信息,它只要清晰简洁地描述问题的症状即可,有时候可能还需要一些上下文信息。在理想情况下,维护者可以在不看代码的情况下就能根据错误信息定位错误产生的原因。一个好的测试不应该在遇到一点小错误时就立刻退出测试,它应该尝试报告更多的相关的错误信息,因为我们可能从多个失败测试的模式中发现错误产生的规律。
|
||||
|
||||
下面的斷言函數比較兩個值,然後生成一個通用的錯誤信息,併停止程序。它很方便使用也確實有效果,但是當測試失敗的時候,打印的錯誤信息卻幾乎是沒有價值的。它併沒有爲快速解決問題提供一個很好的入口。
|
||||
下面的断言函数比较两个值,然后生成一个通用的错误信息,并停止程序。它很方便使用也确实有效果,但是当测试失败的时候,打印的错误信息却几乎是没有价值的。它并没有为快速解决问题提供一个很好的入口。
|
||||
|
||||
```Go
|
||||
import (
|
||||
@@ -25,7 +25,7 @@ func TestSplit(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
從這個意義上説,斷言函數犯了過早抽象的錯誤:僅僅測試兩個整數是否相同,而放棄了根據上下文提供更有意義的錯誤信息的做法。我們可以根據具體的錯誤打印一個更有價值的錯誤信息,就像下面例子那樣。測試在隻有一次重複的模式出現時引入抽象。
|
||||
从这个意义上说,断言函数犯了过早抽象的错误:仅仅测试两个整数是否相同,而放弃了根据上下文提供更有意义的错误信息的做法。我们可以根据具体的错误打印一个更有价值的错误信息,就像下面例子那样。测试在只有一次重复的模式出现时引入抽象。
|
||||
|
||||
```Go
|
||||
func TestSplit(t *testing.T) {
|
||||
@@ -39,10 +39,10 @@ func TestSplit(t *testing.T) {
|
||||
}
|
||||
```
|
||||
|
||||
現在的測試不僅報告了調用的具體函數、它的輸入和結果的意義;併且打印的眞實返迴的值和期望返迴的值;併且卽使斷言失敗依然會繼續嚐試運行更多的測試。一旦我們寫了這樣結構的測試,下一步自然不是用更多的if語句來擴展測試用例,我們可以用像IsPalindrome的表驅動測試那樣來準備更多的s和sep測試用例。
|
||||
现在的测试不仅报告了调用的具体函数、它的输入和结果的意义;并且打印的真实返回的值和期望返回的值;并且即使断言失败依然会继续尝试运行更多的测试。一旦我们写了这样结构的测试,下一步自然不是用更多的if语句来扩展测试用例,我们可以用像IsPalindrome的表驱动测试那样来准备更多的s和sep测试用例。
|
||||
|
||||
前面的例子併不需要額外的輔助函數,如果有可以使測試代碼更簡單的方法我們也樂意接受。(我們將在13.3節看到一個類似reflect.DeepEqual輔助函數。)開始一個好的測試的關鍵是通過實現你眞正想要的具體行爲,然後才是考慮然後簡化測試代碼。最好的接口是直接從庫的抽象接口開始,針對公共接口編寫一些測試函數。
|
||||
前面的例子并不需要额外的辅助函数,如果有可以使测试代码更简单的方法我们也乐意接受。(我们将在13.3节看到一个类似reflect.DeepEqual辅助函数。)开始一个好的测试的关键是通过实现你真正想要的具体行为,然后才是考虑然后简化测试代码。最好的接口是直接从库的抽象接口开始,针对公共接口编写一些测试函数。
|
||||
|
||||
**練習11.5:** 用表格驅動的技術擴展TestSplit測試,併打印期望的輸出結果。
|
||||
**练习11.5:** 用表格驱动的技术扩展TestSplit测试,并打印期望的输出结果。
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user