TDD是測試驅動開發(Test-Driven Development)的英文簡稱,是敏捷開發中的一項核心實踐和技術,也是一種設計方法論。TDD的原理是在開發功能程式碼之前,先編寫單元測試用例程式碼,測試程式碼確定需要編寫什麼產品程式碼。TDD雖是敏捷方法的核心實踐,但不只適用於XP(Extreme Programming),同樣可以適用於其他開發方法和過程。
TDD的基本思路就是通過測試來推動整個開發的進行,但測試驅動開發並不只是單純的測試工作,而是把需求分析,設計,品質控制量化的過程。其基本流程圖如下:
1、編寫測試
在測試中我們測試Repeat函數,希望通過Repeat函數,返回一個字串,該字串包含5個傳入的字元引數。
在iteration/repeat_test.go檔案下編寫測試程式碼如下:
package iteration
import "testing"
func TestRepeat(t *testing.T) {
repeated := Repeat("a")
expected := "aaaaa"
if repeated != expected {
t.Errorf("expected '%q' but got '%q'", expected, repeated)
}
}
2、執行測試得到失敗的結果
由於沒有定義Repeat函數,此時執行測試會報錯,執行測試結果如下:
3、編寫可以編譯的實現
嚴格遵守TDD方法的步驟與原則,現在只需讓程式碼可編譯,這樣你就可以檢查測試用例能否通過。
在iteration/repeat.go檔案下編寫程式碼如下:
package iteration
func Repeat(character string) string {
return ""
}
4、執行測試得到失敗的結果
在此已經定義了Repeat函數,接下來就可以進一步執行測試程式碼裡面的具體內容,但是執行測試的結果也會錯誤,這是因為Repeat函數定義的問題。執行測試結果如下:
5、編寫可以通過測試的實現
根據上一步的執行測試結果以及測試程式碼的要求,重新編寫符合測試要求的Repeat函數,由於已經知道了測試程式碼的具體內容,這一步可以通過需求寫出Repeat函數。
在iteration/repeat.go檔案下重新編寫程式碼如下:
package iteration
func Repeat(character string) string {
var repeated string
for i := 0; i < 5; i++ {
repeated = repeated + character
}
return repeated
}
6、執行測試得到成功的結果
對Repeat函數的重寫滿足了測試程式碼的需求,因此執行測試會得到成功的結果。執行測試結果如下:
7、重構
雖然程式碼repeat.go檔案中的程式碼已經通過了測試,但是其程式碼的規範性和簡潔性還是存在很多問題,所以需要我們對程式碼進行重構,重構程式碼要求在不改變程式碼的邏輯和功能的前提下,儘可能的簡化程式碼。簡化的目的有增強程式碼的可讀性、加快程式碼的執行速度等等。常見的簡化方法就是重用程式碼(將頻繁使用的變數、常數以及函數另外定義出來,這樣就可以在各個地方呼叫此變數、常數、函數即可)。在這裡對repeat.go重構如下:
package iteration
const repeatCount = 5
func Repeat(character string) string {
var repeated string
for i := 0; i < repeatCount; i++ {
repeated += character
}
return repeated
}
基於TDD週期具體完成「迭代」章節的例子之後,還可以在此基礎上編寫基準測試。在 Go 中編寫基準測試(benchmarks)是該語言的另一個一級特性,它與在TDD中的編寫測試步驟非常相似。
在iteration/reoeat_test.go的原基礎上新增如下基準測試的程式碼:
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
Repeat("a")
}
}
testing.B 可使你存取隱性命名(cryptically named)b.N。基準測試執行時,程式碼會執行 b.N 次,並測量需要多長時間。程式碼執行的次數不會對你產生影響,測試框架會選擇一個它所認為的最佳值,以便讓你獲得更合理的結果。
用 go test -bench=. 來執行基準測試。(如果在 Windows Powershell 環境下使用 go test -bench=".")。執行測試結果如下:
這裡要求Repeat函數可以通過傳入一個引數來指定字元重複的次數,我們修改測試程式碼如下:
package iteration
import "testing"
func TestRepeat(t *testing.T) {
repeated := Repeat("a", 6)
expected := "aaaaaa"
if repeated != expected {
t.Errorf("expected %q but got %q", expected, repeated)
}
}
由於Repeat函數的引數發生改變,執行測試會得到失敗的結果。測試結果如下:
修改主程式碼使得測試通過,程式碼修改如下:
package iteration
//Repeat a string with
func Repeat(character string, Readcount int) string {
var repeated string
for i := 0; i < Readcount; i++ {
repeated += character
}
return repeated
}
此時執行測試會得到成功的結果。執行測試如下:
為了完善函數檔案,我們還需要寫一個範例測試。在repeat_test.go檔案裡面加入一個範例測試函數ExampleRepeat,該函數程式碼如下:
func ExampleRepeat() {
str := Repeat("b", 10)
fmt.Println(str)
//Output: bbbbbbbbbb
}
執行測試結果如下:
這表明測試函數和範例測試函數都執行成功。此時檢視函數檔案,發現該函數檔案已經包含範例測試部分。
檢視strings包檔案,部分函數如下:
對Compare、ToLower函數進行編寫應用測試,測試程式碼可簡單寫成如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println("compare:", strings.Compare("a", "b")) //Output: -1
fmt.Println("tolower:", strings.ToLower("ABC")) // Output: abc
}
執行測試程式碼得到的結果如下:
1、編寫測試
在BubbleSort/BubbleSort_test.go檔案下編寫測試程式碼如下:
package BubbleSort
import (
"testing"
)
func TestBubbleSort(t *testing.T) {
arr := [10]int{7, 6, 3, 9, 5, 0, 1, 4, 2, 8}
sorted := BubbleSort(arr)
expected := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := 0; i < 10; i++ {
if sorted[i] != expected[i] {
t.Errorf("expected %v but got %v", expected, sorted)
}
}
}
2、執行測試得到失敗的結果
由於沒有定義BubbleSortt函數,此時執行測試會報錯,執行測試結果如下:
3、編寫可以編譯的實現
嚴格遵守TDD方法的步驟與原則,現在只需讓程式碼可編譯,這樣你就可以檢查測試用例能否通過。
在BubbleSort/BubbleSort.go檔案下編寫程式碼如下:
package BubbleSort
func BubbleSort(arr [10]int) [10]int {
return arr
}
4、執行測試得到失敗的結果
在此已經定義了BubbleSort函數,接下來就可以進一步執行測試程式碼裡面的具體內容,但是執行測試的結果也會錯誤,這是因為BubbleSortt函數定義的問題。執行測試結果如下:
5、編寫可以通過測試的實現
根據上一步的執行測試結果以及測試程式碼的要求,重新編寫符合測試要求的BubbleSort函數,由於已經知道了測試程式碼的具體內容,這一步可以通過需求寫出BubbleSort函數。
在BubbleSort/BubbleSort.go檔案下重新編寫程式碼如下:
package BubbleSort
//BubbleSort sort a array
func BubbleSort(arr [10]int) [10]int {
for i := 0; i < 9; i++ {
for j := 0; j < 9-i; j++ {
if arr[j] > arr[j+1] {
temp := arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr
}
6、執行測試得到成功的結果
對BubbleSort函數的重寫滿足了測試程式碼的需求,因此執行測試會得到成功的結果。執行測試結果如下:
7、重構
根據前面提到的方法,對BubbleSort.go重構如下:
package BubbleSort
const count = 10
//BubbleSort sort a array
func BubbleSort(arr [10]int) [10]int {
for i := 0; i < count-1; i++ {
for j := 0; j < count-1-i; j++ {
if arr[j] > arr[j+1] {
temp := arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr
}
在BubbleSort/BubbleSort.go的原基礎上新增如下基準測試的程式碼:
func BenchmarkBubbleSort(b *testing.B) {
for i := 0; i < b.N; i++ {
arr := [10]int{7, 6, 3, 9, 5, 0, 1, 4, 2, 8}
BubbleSort(arr)
}
}
用 go test -bench=. 來執行基準測試。(如果在 Windows Powershell 環境下使用 go test -bench=".")。執行測試結果如下: