本文将介绍一种应用于Go语言中的编程技巧TDD(Test Driven Development测试驱动开发),这一技巧主要得益于Go语言强大的testing包。

参考书目:《Go Design Pattern》

Testing与TDD

  当我们开始实现一段代码时,我们可能不会想到为这段代码加上测试,因为这段代码的体量还不算庞大。但随着代码量的增大,我们需要测试一些功能就会变得异常困难,这主要是因为代码量的提升和相互之间的调用导致我们无法快速的定位到出现问题的代码。所以在开始代码编写时就考虑功能测试是有必要的。

  Golang有一个强大的测试包(testing),可以让您轻松地在TDD环境中工作。通过这个包,我们可以很方便的检查部分代码,而无需编写一个调用整个程序的main函数。

testing包

  测试对于每种语言来说都至关重要,go语言原生的提供了这个包,你无需通过第三方包或应用来测试你的代码。接下来我们讨论如何应用testing这个包。

  首先我们需要一段需要测试的代码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"os"
"strconv"
)

func sum(a, b int) int {
return a + b
}

func main() {
a, _ := strconv.Atoi(os.Args[1])
b, _ := strconv.Atoi(os.Args[2])

result := sum(a, b)
fmt.Printf("The sum of %d and %d is %d\n", a, b, result)
}

这段代码非常简单通过命令行读入两个参数,并将他们相加,你可以在命令行中运行他们通过以下命令:

1
$ go run sum.go 1 2

接下来我们将创建一个测试文件来对这段代码进行测试,按照惯例,你的测试文件应该是在你正在测试的文件名的基础上加上_test后缀。所以,测试文件应该命名为sum_test.go。具体内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "testing"

func TestSum(t *testing.T) {
a := 2
b := 3
expected := 5

res := Sum(a, b)
if res != expected {
t.Errorf("Sum function error: %d + %d isn't %d",a, b, res)
}
}

go语言中的测试函数通过以Test开头的方式来编写,同时传入一个指针参数t *testing.T,可以通过一下命令运行测试:

1
$ go test -v

这里的参数v表示我们需要从test中接收详细的输出。也可以加入-cover参数来检查测试代码的覆盖率,他会返回测试代码执行到的行占代码总行数的比例。

TDD

  所谓TDD,就是我们在实现我们的函数之前先为它写个测试,我们用一个乘法的例子来展示TDD的思想。我们首先给出函数的声明,但不实现,代码如下:

1
2
3
4
5
package main

func multiply(a, b int) int {
return 0
}

紧接着我们实现测试函数,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "testing"

func TestMultiply(t *testing.T) {
a := 1
b := 2
expected := 2

res := multiply(a, b)
if res != expected {
t.Errorf("Sum function error: %d * %d isn't %d", a, b, res)
}
}

此时运行go test一定会提示FAIL,因为1 * 2 != 0。目前我们有一个函数的声明和一个失败的测试,在此基础上,我们就可以开始真正乘法功能的实现了。代码如下:

1
2
3
4
5
package main

func multiply(a, b int) int {
return a * b
}

运行go test之后你会看到成功的标志,虽然我们这里没有提供一个完整的main函数去运行multiply,但我们还是测试了我们的实现是否正确,这就是go语言中testing包的强大之处。

总结

  当我第一次接触到这种技巧的时候也是非常不习惯,但当后期我的代码越来越复杂时,我发现这种编程技巧可以帮助你很好的定位到你代码中的错误,你可以在*_test.go中写不同的测试用于测试不同的函数,甚至是同一函数的不同功能,你只需要在go test的参数中加入-run=*来进行测试函数的匹配,这里-run是进行正则匹配的,你无需为其提供完整的函数名(函数名不要包含Test)。

  这篇文章到这里就结束了,可能有些唐突,希望你可以感受到TDD的魅力。