Go的单元测试

单元测试一般用来测试自己写的代码逻辑是否有问题,能不能按照自己的预期执行,便于自己在上线之前检验代码质量。

在我自己使用单元测试的过程中,我自己一般都是针对某个函数进行测试,判断这个函数是否能够达到预期效果。为了在Go中使用单元测试,我们需要在xxx_test.go文件中导入testing包,通过go test命令实现自动执行如下形式的函数:

func TestFuncName(*testing.T)

需要注意的是:FuncName的函数名第一个字母不能小写

在上面的测试函数中,如果需要发送失败消息我们可以使用Error或者FailFatal这些方法,执行成功的话我们也可以使用Log函数输出一些信息。

在编写单元测试的时候,我们需要创建一个以_test.go结尾的文件,文件中包含了Test_FuncName函数。并且这两个文件放在同一个package下。通过执行go test xxx.go来进行单元测试。

单元测试示例

在这我将会在strings.go中写个方法Contains,然后在strings_test.go文件中写一个测试函数TestContains,并且我将这两个文件放在同一个package下,具体如下所示:

strings.go

func Contains(s, substr string) bool {
    return strings.Contains(s, substr)
}

strings_test.go

func TestContains(t *testing.T) {
        res := basic.Contains("res", "e")

        if res == true {
                t.Log("the result is OK")
        } else {
                t.Fatal("the result is wrong")
        }
}

然后打开cmd窗口,输入命令go test -v .\strings_test.go,可以看到输出结果如下:

=== RUN   TestContains
    TestContains: strings_test.go:12: the result is OK
--- PASS: TestContains (0.00s)
PASS
ok      command-line-arguments  (cached)

Table-Driven Test(TDT)

上面的测试中只输入了一个case,并没有实现case覆盖,测试结果可能会不全。所以如果在一个测试中需要测试多个case,如果我们直接在代码中输入多个case,这将会很费时费力。但是不需要担心,我们可以使用table-driven的方式来实现测试函数。为了实现多个case测试的示例,我在原来的文件中分别实现一个AddTest_Add函数,示例如下:

strings.go

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

strings_test.go

func TestAdd(t *testing.T) {
        // define table
        var addtests = []struct {
                a int
                b int
                res int    // expected result
        }{
                {1,1,2},
                {2,3,5},
                {3,4,7},
                {5,6,11},
                {6,5,11},
                {1,22,23},
        }

        for _, sum := range addtests {
                actual := basic.Add(sum.a, sum.b)

                if actual != sum.res {
                        t.Errorf("Add(%d + %d ) = %d, expected result is %d", sum.a, sum.b, actual ,sum.res)
                }
        }
}

输入命令go test -v .\strings_test.go得到如下结果

=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      command-line-arguments  0.222s

testing的结构体

  • B : 压力测试
  • BenchmarkResult : 压力测试结果
  • Cover : 代码覆盖率相关结构体
  • CoverBlock : 代码覆盖率相关结构体
  • InternalBenchmark : 内部使用的结构体
  • InternalExample : 内部使用的结构体
  • InternalTest : 内部使用的结构体
  • M : main 测试使用的结构体
  • PB : Parallel benchmarks 并行测试使用的结构体
  • T : 普通测试用例
  • TB : 测试用例的接口

testing的通用方法

  1. 碰到断言错误,会判断这个测试用例失败,可能会使用到

Fail : case失败,继续后面的测试用例

FaileNow: case失败,终止测试

  1. 碰到断言错误时希望跳过这个错误,但是不希望标识case失败,使用

SkipNow : case跳过,终止测试

  1. 只希望在一个地方打印信息,使用

Log: 输出信息

Logf: 输出格式化的信息

  1. 希望跳过这个case并且打印信息

Skip: = Log + SkipNow

Skipf: = Logf + SkipNow

  1. case失败的时候打印出信息,并且中断测试用例

Fatal: = Log + FailNow

Fatalf: = Logf + FailNow

  1. case失败的时候打印出信息,并且希望测试继续

Error: = Log + Fail

Errorf: = Logf + Fail

参考文档