【Golang】testing - 单元测试

testing 为 Go 语言 package 提供自动化测试的支持。通过 go test 命令,能够自动执行如下形式的任何函数:

func TestXxx(*testing.T)

注意:Xxx 可以是任何字母数字字符串,但是第一个字母不能是小些字母。

在这些函数中,使用 Error, Fail 或相关方法来发出失败信号。

要编写一个新的测试套件,需要创建一个名称以 _test.go 结尾的文件,该文件包含 TestXxx 函数,如上所述。 将该文件放在与被测试的包相同的包中。该文件将被排除在正常的程序包之外,但在运行 “ go test ” 命令时将被包含。 有关详细信息,请运行 “ go help test ” 和 “ go help testflag ” 了解。

如果有需要,可以调用 *T 和 *B 的 Skip 方法,跳过该测试或基准测试:

func TestTimeConsuming(t *testing.T) {
    if testing.Short() {
        t.Skip("skipping test in short mode.")
    }
    ...
}
第一个单元测试

要测试的代码:

func Fib(n int) int {
        if n < 2 {
                return n
        }
        return Fib(n-1) + Fib(n-2)
}

测试代码:

func TestFib(t *testing.T) {
    var (
        in       = 7
        expected = 13
    )
    actual := Fib(in)
    if actual != expected {
        t.Errorf("Fib(%d) = %d; expected %d", in, actual, expected)
    }
}

执行 go test .,输出:

$ go test .
ok      chapter09/testing    0.007s

表示测试通过。

我们将 Sum 函数改为:

func Fib(n int) int {
        if n < 2 {
                return n
        }
        return Fib(n-1) + Fib(n-1)
}

再执行 go test .,输出:

$ go test .
--- FAIL: TestSum (0.00s)
    t_test.go:16: Fib(10) = 64; expected 13
FAIL
FAIL    chapter09/testing    0.009s
Table-Driven Test

测试讲究 case 覆盖,按上面的方式,当我们要覆盖更多 case 时,显然通过修改代码的方式很笨拙。这时我们可以采用 Table-Driven 的方式写测试,标准库中有很多测试是使用这种方式写的。

func TestFib(t *testing.T) {
    var fibTests = []struct {
        in       int // input
        expected int // expected result
    }{
        {1, 1},
        {2, 1},
        {3, 2},
        {4, 3},
        {5, 5},
        {6, 8},
        {7, 13},
    }

    for _, tt := range fibTests {
        actual := Fib(tt.in)
        if actual != tt.expected {
            t.Errorf("Fib(%d) = %d; expected %d", tt.in, actual, tt.expected)
        }
    }
}

因为我们使用的是 t.Errorf,其中某个 case 失败,并不会终止测试执行。

T 类型

单元测试中,传递给测试函数的参数是 *testing.T 类型。它用于管理测试状态并支持格式化测试日志。测试日志会在执行测试的过程中不断累积,并在测试完成时转储至标准输出。

当一个测试的测试函数返回时,又或者当一个测试函数调用 FailNow、 Fatal、Fatalf、SkipNow、Skip 或者 Skipf 中的任意一个时,该测试即宣告结束。跟 Parallel 方法一样,以上提到的这些方法只能在运行测试函数的 goroutine 中调用。

至于其他报告方法,比如 Log 以及 Error 的变种, 则可以在多个 goroutine 中同时进行调用。

报告方法

上面提到的系列包括方法,带 f 的是格式化的,格式化语法参考 fmt 包。

T 类型内嵌了 common 类型,common 提供这一系列方法,我们经常会用到的(注意,这里说的测试中断,都是指当前测试函数):

1)当我们遇到一个断言错误的时候,标识这个测试失败,会使用到:

Fail: 测试失败,测试继续,也就是之后的代码依然会执行
FailNow: 测试失败,测试中断

在 FailNow 方法实现的内部,是通过调用 runtime.Goexit() 来中断测试的。

2)当我们遇到一个断言错误,只希望跳过这个错误,但是不希望标识测试失败,会使用到:

SkipNow: 跳过测试,测试中断

在 SkipNow 方法实现的内部,是通过调用 runtime.Goexit() 来中断测试的。
3)当我们只希望打印信息,会用到 :

Log: 输出信息
Logf: 输出格式化的信息

注意:默认情况下,单元测试成功时,它们打印的信息不会输出,可以通过加上 -v 选项,输出这些信息。但对于基准测试,它们总是会被输出。

4)当我们希望跳过这个测试,并且打印出信息,会用到:

Skip: 相当于 Log + SkipNow
Skipf: 相当于 Logf + SkipNow

5)当我们希望断言失败的时候,标识测试失败,并打印出必要的信息,但是测试继续,会用到:

Error: 相当于 Log + Fail
Errorf: 相当于 Logf + Fail

6)当我们希望断言失败的时候,标识测试失败,打印出必要的信息,但中断测试,会用到:

Fatal: 相当于 Log + FailNow
Fatalf: 相当于 Logf + FailNow
发布了363 篇原创文章 · 获赞 14 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/105347761