教程学习
先写测试
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_test.go
尝试运行测试
./repeat_test.go:6:14: undefined: Repeat
使用最少的代码让失败的测试跑起来
package iteration
func Repeat(character string) string {
return ""
}
结果
repeat_test.go:10: expected 'aaaaa' but got ''
代码补充完整,让它能通过测试
func Repeat(character string) string {
var repeated string
for i := 0; i < 5; i++ {
repeated = repeated + character
}
return repeated
}
与其它语言如 C,Java 或 JavaScript 不同,在 Go 中 for 语句前导条件部分并没有圆括号,而且大括号 { } 是必须的。
我们目前都是使用 := 来声明和初始化变量。然后 := 只是两个步骤的简写。这里我们使用显式的版本来声明一个 string 类型的变量。我们还可以使用 var 来声明函数。
重构
现在是时候重构并引入另一个构造(construct)+= 赋值运算符。
const repeatCount = 5
func Repeat(character string) string {
var repeated string
for i := 0; i < repeatCount; i++ {
repeated += character
}
return repeated
}
+=是自增赋值运算符(Add AND assignment operator),它把运算符右边的值加到左边并重新赋值给左边。它在其它类型也可以使用,比如整数类型。
基准测试
在 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=".")
练习
修改测试代码,以便调用者可以指定字符重复的次数,然后修复代码
修改测试代码如下:
package iteration
import “testing”
import “os”
import “strconv”
func TestRepeat(t *testing.T){
repeated := Repeat(“a”)
var expected string
var b int
s, err := strconv.ParseInt(os.Args[len(os.Args)-1],10,32)
if err != nil{
panic(err)
}
b = int(s)
for i := 0;i < b;i++{
expected += “a”
}
if repeated != expected{
t.Errorf(“expected ‘%q’ but got ‘%q’”,expected,repeated)
}
}
写一个 ExampleRepeat 来完善你的函数文档
ExampleRepeat:
func ExampleRepeat(){
s := Repeat(“a”)
fit.Println(s)
}
查看函数文档
安装godoc:
go env -w GO111MODULE=on
go env -w GOPROXY=“https://goproxy.io,direct”
go get golang.org/x/tools/cmd/godoc
看一下 strings 包。找到你认为可能有用的函数,并对它们编写一些测试。投入时间学习标准库会慢慢得到回报。
TDD
基本概念
TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。
原理
TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。
基本思路
TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。
基本原则
独立测试:不同代码的测试应该相互独立,一个类对应一个测试类(对于C代码或C++全局函数,则一个文件对应一个测试文件),一个函数对应一个测试函数。用例也应各自独立,每个用例不能使用其他用例的结果数据,结果也不能依赖于用例执行顺序。 一个角色:开发过程包含多种工作,如:编写测试代码、编写产品代码、代码重构等。做不同的工作时,应专注于当前的角色,不要过多考虑其他方面的细节。
测试列表:代码的功能点可能很多,并且需求可能是陆续出现的,任何阶段想添加功能时,应把相关功能点加到测试列表中,然后才能继续手头工作,避免疏漏。
测试驱动:即利用测试来驱动开发,是TDD的核心。要实现某个功能,要编写某个类或某个函数,应首先编写测试代码,明确这个类、这个函数如何使用,如何测试,然后在对其进行设计、编码。
先写断言:编写测试代码时,应该首先编写判断代码功能的断言语句,然后编写必要的辅助语句。
可测试性:产品代码设计、开发时的应尽可能提高可测试性。每个代码单元的功能应该比较单纯,“各家自扫门前雪”,每个类、每个函数应该只做它该做的事,不要弄成大杂烩。尤其是增加新功能时,不要为了图一时之便,随便在原有代码中添加功能,对于C++编程,应多考虑使用子类、继承、重载等OO方法。
及时重构:对结构不合理,重复等“味道”不好的代码,在测试通过后,应及时进行重构。
小步前进:软件开发是复杂性非常高的工作,小步前进是降低复杂性的好办法。
优缺点
优点:在任意一个开发节点都可以拿出一个可以使用,含少量bug并具一定功能和能够发布的产品。
缺点:增加代码量。测试代码是系统代码的两倍或更多,但是同时节省了调试程序及挑错时间。
使用TDD思想实现快排
先写测试
package quicksort
import "testing"
var arr = [] int {1, 3, 5, 8, 9, 4, 2, 7, 10, 6, 12, 11}
var maxn int = 12
func TestQuicksort(t *testing.T){
Quicksort(arr, 0, 11)
expected := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
flag := true
for i:=0 ; i<12 ; i++{
if arr[i] != expected[i]{
flag = false
}
}
if flag == false{
t.Errorf("Expected %v but got %v", expected, arr)
}
}
使用最少的代码让失败的测试跑起来
写一个简单的Quicksort函数,但此时的数组并没有排序,仍然按照原顺序输出
package quicksort
func Quicksort(arr []int, start int, end int){
return
}
代码补充完整,让它能通过测试
完善Quicksort函数
package quicksort
func Quicksort(arr []int, start int, end int){
if start >= end{
return
}
num := arr[(start+end)/2]
i := start
j := end
for arr[j] > num{
j--
}
for arr[i] < num{
i++
}
temp := arr[i]
arr[i] = arr[j]
arr[j] = temp
i++
j--
if i < end{
Quicksort(arr, i, end)
}
if j > start{
Quicksort(arr, start, j)
}
}
基准测试
func BenchmarkQuicksort(b *testing.B){
for i:=0 ; i<b.N ; i++{
var arr = []int {1, 3, 5, 8, 9, 4, 2, 7, 10, 6, 12, 11}
Quicksort(arr, 0, 11)
}
}