go語言測試之TDD

2020-09-24 17:00:27

一、TDD理解

TDD定義

TDD測試驅動開發(Test-Driven Development)的英文簡稱,是敏捷開發中的一項核心實踐和技術,也是一種設計方法論。TDD的原理是在開發功能程式碼之前,先編寫單元測試用例程式碼,測試程式碼確定需要編寫什麼產品程式碼。TDD雖是敏捷方法的核心實踐,但不只適用於XP(Extreme Programming),同樣可以適用於其他開發方法和過程。
TDD的基本思路就是通過測試來推動整個開發的進行,但測試驅動開發並不只是單純的測試工作,而是把需求分析,設計,品質控制量化的過程。其基本流程圖如下:
在這裡插入圖片描述


基於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
}

基準測試(benchmarks)

基於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
}

此時執行測試會得到成功的結果。執行測試如下:

在這裡插入圖片描述

寫一個 ExampleRepeat 來完善你的函數檔案

為了完善函數檔案,我們還需要寫一個範例測試。在repeat_test.go檔案裡面加入一個範例測試函數ExampleRepeat,該函數程式碼如下:

func ExampleRepeat() {
	str := Repeat("b", 10)
	fmt.Println(str)
	//Output: bbbbbbbbbb
}

執行測試結果如下:
在這裡插入圖片描述
這表明測試函數和範例測試函數都執行成功。此時檢視函數檔案,發現該函數檔案已經包含範例測試部分。
在這裡插入圖片描述


看一下 strings 包。找到你認為可能有用的函數,並對它們編寫一些測試

檢視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
}

執行測試程式碼得到的結果如下:
在這裡插入圖片描述

三、TDD應用:go語言實現氣泡排序演演算法

基於TDD週期完成氣泡排序演演算法

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
}

基準測試(benchmarks)

在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=".")。執行測試結果如下:
在這裡插入圖片描述