# 第十一章 測試
Maurice Wilkes,第一個存儲程序計算機EDSAC的設計者,1949年他在實驗室爬樓梯時有一個頓悟。在《計算機先驅回憶錄》(Memoirs of a Computer Pioneer)里,他回憶到:“忽然間有一種醍醐灌頂的感覺,我整個后半生的美好時光都將在尋找程序BUG中度過了”。肯定從那之后的大部分正常的碼農都會同情Wilkes過分悲觀的想法,雖然也許會有人困惑于他對軟件開發的難度的天真看法。
現在的程序已經遠比Wilkes時代的更大也更復雜,也有許多技術可以讓軟件的復雜性可得到控制。其中有兩種技術在實踐中證明是比較有效的。第一種是代碼在被正式部署前需要進行代碼評審。第二種則是測試,也就是本章的討論主題。
我們說測試的時候一般是指自動化測試,也就是寫一些小的程序用來檢測被測試代碼(產品代碼)的行為和預期的一樣,這些通常都是精心設計的執行某些特定的功能或者是通過隨機性的輸入待驗證邊界的處理。
軟件測試是一個巨大的領域。測試的任務可能已經占據了一些程序員的部分時間和另一些程序員的全部時間。和軟件測試技術相關的圖書或博客文章有成千上萬之多。對于每一種主流的編程語言,都會有一打的用于測試的軟件包,同時也有大量的測試相關的理論,而且每種都吸引了大量技術先驅和追隨者。這些都足以說服那些想要編寫有效測試的程序員重新學習一套全新的技能。
Go語言的測試技術是相對低級的。它依賴一個go test測試命令和一組按照約定方式編寫的測試函數,測試命令可以運行這些測試函數。編寫相對輕量級的純測試代碼是有效的,而且它很容易延伸到基準測試和示例文檔。
在實踐中,編寫測試代碼和編寫程序本身并沒有多大區別。我們編寫的每一個函數也是針對每個具體的任務。我們必須小心處理邊界條件,思考合適的數據結構,推斷合適的輸入應該產生什么樣的結果輸出。編寫測試代碼和編寫普通的Go代碼過程是類似的;它并不需要學習新的符號、規則和工具。
- 前言
- Go語言起源
- Go語言項目
- 本書的組織
- 更多的信息
- 致謝
- 入門
- Hello, World
- 命令行參數
- 查找重復的行
- GIF動畫
- 獲取URL
- 并發獲取多個URL
- Web服務
- 本章要點
- 程序結構
- 命名
- 聲明
- 變量
- 賦值
- 類型
- 包和文件
- 作用域
- 基礎數據類型
- 整型
- 浮點數
- 復數
- 布爾型
- 字符串
- 常量
- 復合數據類型
- 數組
- Slice
- Map
- 結構體
- JSON
- 文本和HTML模板
- 函數
- 函數聲明
- 遞歸
- 多返回值
- 錯誤
- 函數值
- 匿名函數
- 可變參數
- Deferred函數
- Panic異常
- Recover捕獲異常
- 方法
- 方法聲明
- 基于指針對象的方法
- 通過嵌入結構體來擴展類型
- 方法值和方法表達式
- 示例: Bit數組
- 封裝
- 接口
- 接口是合約
- 接口類型
- 實現接口的條件
- flag.Value接口
- 接口值
- sort.Interface接口
- http.Handler接口
- error接口
- 示例: 表達式求值
- 類型斷言
- 基于類型斷言識別錯誤類型
- 通過類型斷言查詢接口
- 類型分支
- 示例: 基于標記的XML解碼
- 補充幾點
- Goroutines和Channels
- Goroutines
- 示例: 并發的Clock服務
- 示例: 并發的Echo服務
- Channels
- 并發的循環
- 示例: 并發的Web爬蟲
- 基于select的多路復用
- 并發的退出
- 示例: 聊天服務
- 基于共享變量的并發
- 競爭條件
- sync.Mutex互斥鎖
- sync.RWMutex讀寫鎖
- 內存同步
- 競爭條件檢測
- 示例: 并發的非阻塞緩存
- Goroutines和線程
- 包和工具
- 包簡介
- 導入路徑
- 包聲明
- 導入聲明
- 包的匿名導入
- 包和命名
- 工具
- 測試
- go test
- 測試函數
- 測試覆蓋率
- 基準測試
- 剖析
- 示例函數
- 反射
- 為何需要反射?
- reflect.Type和reflect.Value
- Display遞歸打印
- 示例: 編碼S表達式
- 通過reflect.Value修改值
- 示例: 解碼S表達式
- 顯示一個類型的方法集
- 幾點忠告
- 底層編程
- unsafe.Sizeof, Alignof 和 Offsetof
- unsafe.Pointer
- 示例: 深度相等判斷
- 通過cgo調用C代碼
- 幾點忠告
- 附錄
- 附錄A:原文勘誤
- 附錄B:作者譯者
- 附錄C:譯文授權
- 附錄D:其它語言