对TDD的理解
什么是TDD
TDD是测试驱动开发(Test-Driven Development),是敏捷开发中的一项核心实践和技术,也是一种设计方法论。
TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD虽是敏捷方法的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。
TDD的优势
提前澄清需求
先写测试可以帮助我们去思考需求,并提前澄清需求细节,而不是代码写到一半才发现不明确的需求。
降低开发者负担
通过明确的流程,让我们一次只关注一个点,思维负担更小。
测试驱动
即利用测试来驱动开发,是TDD的核心。要实现某个功能,要编写某个类或某个函数,应首先编写测试代码,明确这个类、这个函数如何使用,如何测试,然后在对其进行设计、编码。
小步前进
软件开发是复杂性非常高的工作,小步前进是降低复杂性的好办法。
参考教程的步骤实践
1. 测试
首先编写测试文件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)
}
}
然后编写一个Repeat(iteration/repeat.go)函数,让测试能够先跑起来
package iteration
// Repeat is a function
func Repeat(character string) string {
return ""
}
接下来就运行go test,看是否测试通过
显然,这时候是无法测试通过的
2. 编写可以通过测试的函数
package iteration
// Repeat is a function
func Repeat(character string) string {
var repeated string
for i := 0; i < 5; i++ {
repeated = repeated + character
}
return repeated
}
此时测试结果为
3. 重构
此时重构并引入另一个构造(construct)+= 赋值运算符
package iteration
// Repeat is a function
func Repeat(character string) string {
var repeated string
for i := 0; i < 5; i++ {
repeated += character //重构 +=
}
return repeated
}
4. 基准测试
在 Go 中编写基准测试(benchmarks)是该语言的另一个一级特性,它与编写测试非常相似。
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=".")
基准测试结果如下所示:
完成参考教程“迭代”章节的练习
1. 修改测试代码,以便调用者可以指定字符重复的次数,然后修复代码
首先修改测试文件
package iteration
import "testing"
func TestRepeat(t *testing.T) {
repeated := Repeat("a", 5)
expected := "aaaaa"
if repeated != expected {
t.Errorf("expected '%q' but got '%q'", expected, repeated)
}
}
此时结果为
显然,此时函数签名不匹配,接下来就修改函数,让测试可以通过
修改repeat函数
package iteration
// Repeat is a function
func Repeat(character string, number int) string {
var repeated string
for i := 0; i < number; i++ {
repeated += character
}
return repeated
}
修改之后再次测试结果为
2. 写一个 ExampleRepeat 来完善你的函数文档
在测试文件中加入一个示例测试函数ExampleRepeat
package iteration
import (
"fmt"
"testing"
)
func ExampleRepeat() {
var temp string
temp = Repeat("r", 8)
fmt.Println(temp)
//output rrrrrrrr
}
3. 看一下 strings 包。找到你认为可能有用的函数,并对它们编写一些测试。
查看strings包,发现有以下常见的函数
这里我选择Contains、Count、Split、ToLower几个函数来编写测试
package string
import (
"strings"
"testing"
)
func TestContains(t *testing.T) {
s := "0123456"
substr := "123"
result := strings.Contains(s, substr)
expected := true
if expected != result {
t.Errorf("expected '%t' but got result '%t'", expected, result)
}
}
func TestCount(t *testing.T) {
s := "cheese"
element := "e"
result := strings.Count(s, element)
expected := 3
if expected != result {
t.Errorf("expected '%d' but got result '%d'", expected, result)
}
}
func TestSplit(t *testing.T) {
s := "a,b,c,d"
element := ","
result := strings.Split(s, element)
expected := [4]string{"a", "b", "c", "d"}
var flag bool
flag = true
for i := 0; i < 4; i++ {
if result[i] != expected[i] {
flag = false
}
}
if flag != true {
t.Errorf("expected '%q' but got result '%q'", expected, result)
}
}
func TestToLower(t *testing.T) {
s := "AbCdeF"
result := strings.ToLower(s)
expected := "abcdef"
if expected != result {
t.Errorf("expected '%q' but got result '%q'", expected, result)
}
}
测试结果如下:
TDD实践(冒泡)
1. 先写测试
package sort
import (
"fmt"
"testing"
)
func ExampleBubbleSort() {
number := [10]int{9, 8, 6, 3, 4, 5, 7, 2, 0, 1}
result := BubbleSort(number)
fmt.Println(result)
//output [0,1,2,3,4,5,6,7,8,9]
}
func TestBubbleSort(t *testing.T) {
number := [10]int{9, 8, 6, 3, 4, 5, 7, 2, 0, 1}
result := BubbleSort(number)
expected := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := 0; i < 10; i++ {
if result[i] != expected[i] {
t.Errorf("expected '%v' but got '%v'", expected, result)//go可以直接输出数组
}
}
}
尝试运行测试,发现运行失败(这是显然的,因为我们都还没有写BubbleSort函数)
2. 编写函数,先让测试运行
package sort
//BubbleSort is a function using for sorting
func BubbleSort(num [10]int) [10]int {
return num
}
现在发现测试可以运行,但是不能通过(就这样输出原数组当然不可能通过)
3. 改写BubbleSort函数,使测试通过
package sort
//BubbleSort is a function use for sorting
func BubbleSort(num [10]int) [10]int {
for i := 0; i < 10; i++ {
for j := i; j < 10; j++ {
if num[i] > num[j] {
temp := num[i]
num[i] = num[j]
num[j] = temp
}
}
}
return num
}
此时测试通过,结果为:
4. 基准测试
func BenchmarkBubbleSort(b *testing.B) {
num := [10]int{6, 5, 3, 7, 4, 2, 0, 9, 1, 8}
for i := 0; i < b.N; i++ {
BubbleSort(num)
}
}
基准测试结果为:
至此,冒泡排序的TDD实现就完成了