在这篇文章中将会学习一下如何在go语言中使用testing包进行功能测试和性能测试。

自动化测试

正如Martin Fowler所说的”在你不知道如何测试代码之前,就不该编写程序。而一旦你完成了程序,测试代码也应该完成。除非测试成功,你不能认为你编写出了可以工作的程序”。测试在软件开发中起到了非常关键的作用,而Martin Fowler所倡导的测试代码和程序同时完成的方式在大型项目中也正在应用,随着质量意识的提高以及DevOps的推行,自动化测试在变得越来越重要。

自动化测试框架

各种语言都有不同的测试框架,而测试因其种类不同,框架也有所不同,而且同等类似功能的框架也有很多,简单列举一部分与go语言的标准库testing作比较如下

语言框架提供者
CCunit第三方
C++Cppunit第三方
JavaJunit第三方
PythonPyUnit第三方->标准库
gotestinggo语言标准库

可以看出作为一门有后发优势的年轻语言,go在设计的时候标准库中含括一些已经得到证实的最佳实践。

go程序测试

通过testing包,go语言编写的程序可以进行功能测试和压力测试(BMT: Benchmark Testing)。如下是在编写测试用例时候需要注意的事项

项目说明
依赖import testing
命令go test
测试文件名必须以_test.go结尾
功能测试用例函数必须以Test开头,其后的函数名不能以小写字母开头,比如Testadd是一个错误的命名
压力测试用例函数必须以Benchmark开头,其后的函数名不能以小写字母开头
功能测试参数testing.T
压力测试参数testing.B
记录测试信息.Log方法, 缺省不会显示,仅在go test -v时会显示
测试控制通过Error/Errorf/FailNow/Fatal/FatalIf等进行测试是否失败或者在何种条件下失败的控制
压力测试go test缺省不会进行压力测试的执行,需要执行压力测试的时候要加上参数-test.bench
压力测试循环体压力测试循环体中会使用test.B.N
测试对象准备

为了学习go语言中如何使用testing标准库,事前准备前面讲解流程控制时使用到的switch-case的例子,以及一个计算加法的函数

项目详细说明
文件名basicfunc.go测试对象文件
package名basicfunc测试对象Package
测试对象函数GetGrade输入分数返回A-D的等级
测试对象函数Add输入两个数字,返回其相加之和

例子代码

[root@liumiaocn test]# cat basicfunc.go
package basicfunc

func GetGrade(score int) string {
        switch {
        case score < 60:
                return "D"
        case score <= 70:
                return "C"
        case score <= 80:
                return "B"
        case score <= 90:
                return "A"
        default:
                return "Undefined"
        }
}

func Add(num1 int, num2 int) int {
        return num1 + num2
}
[root@liumiaocn test]#
功能测试用例
[root@liumiaocn test]# cat func_test.go
package basicfunc

import "testing"

func TestBasic(test *testing.T) {
        grade := GetGrade(40)
        if grade != "D" {
                test.Error("Test Case failed.")
        }

}

func TestAddfunc(test *testing.T) {
        sum := Add(1, 1)
        if sum == 2 {
                test.Log("Passed: 1 + 1 == 2 ")
        } else {
                test.Log("Failed: 1 + 1 == 2 ")
        }
}
[root@liumiaocn test]#
执行测试
[root@liumiaocn test]# go test
PASS
ok      _/tmp/goprj/test        0.002s
[root@liumiaocn test]#

显示执行详细信息

[root@liumiaocn test]# go test -v
=== RUN   TestBasic
--- PASS: TestBasic (0.00s)
=== RUN   TestAddfunc
--- PASS: TestAddfunc (0.00s)
        func_test.go:16: Passed: 1 + 1 == 2
PASS
ok      _/tmp/goprj/test        0.002s
[root@liumiaocn test]#

压力测试用例

增加压力测试用例后代码如下

[root@liumiaocn test]# cat func_test.go
package basicfunc

import "testing"

func TestBasic(test *testing.T) {
        grade := GetGrade(40)
        if grade != "D" {
                test.Error("Test Case failed.")
        }

}

func TestAddfunc(test *testing.T) {
        sum := Add(1, 1)
        if sum == 2 {
                test.Log("Passed: 1 + 1 == 2 ")
        } else {
                test.Log("Failed: 1 + 1 == 2 ")
        }
}

func BenchmarkAddfunc(bmtest *testing.B) {
        for cnt := 0; cnt < bmtest.N; cnt++ {
                Add(1, 1)
        }
}
[root@liumiaocn test]#
执行测试

通过压力测试可以看到,Add函数执行了2000000000次,平均执行时间0.33纳秒。

[root@liumiaocn test]# go test -bench=.
BenchmarkAddfunc        2000000000               0.33 ns/op
PASS
ok      _/tmp/goprj/test        0.691s
[root@liumiaocn test]#

详细信息

[root@liumiaocn test]# go test -bench=. -v
=== RUN   TestBasic
--- PASS: TestBasic (0.00s)
=== RUN   TestAddfunc
--- PASS: TestAddfunc (0.00s)
        func_test.go:16: Passed: 1 + 1 == 2
BenchmarkAddfunc        2000000000               0.35 ns/op
PASS
ok      _/tmp/goprj/test        0.747s
[root@liumiaocn test]#
总结

go语言标准包的testing提供了功能性测试和压力测试常用的方法的框架,可以非常方便地利用其进行自动化测试。