golang单元测试简记

golang中的测试类型

类型 格式 作用
测试函数 函数名前缀为Test 测试程序的一些逻辑行为是否正确
基准函数 函数名前缀为Benchmark 测试函数的性能
示例函数 函数名前缀为Example 为文档提供示例文档

在goland中快速生成测试代码

以字符串分割函数为例,它在作用就是分割字符串,并且返回分割后的切片:

// split/split.go

package split

import "strings"

// split package with a single split function.

// Split slices s into all substrings separated by sep and
// returns a slice of the substrings between those separators.
func Split(s, sep string) (result []string) {
    i := strings.Index(s, sep)

    for i > -1 {
        result = append(result, s[:i])
        s = s[i+len(sep):]
        i = strings.Index(s, sep)
    }
    result = append(result, s)
    return
}

右击->Gernate->Tests for file


在与被测试的包相同的包中,它会创建一个名称以 _test.go 结尾的文件,该文件包含 TestXxx 函数。该文件将被排除在正常的程序包之外,但在运行 “go test” 命令时将被包含。
可以看到名为“split_test.go”的test文件,初始内容为

package split

import (
    "reflect"
    "testing"
)

func TestSplit(t *testing.T) {
    type args struct {
        s   string
        sep string
    }
    tests := []struct {
        name       string
        args       args
        wantResult []string
    }{
        // TODO: Add test cases.
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if gotResult := Split(tt.args.s, tt.args.sep); !reflect.DeepEqual(gotResult, tt.wantResult) {
                t.Errorf("Split() = %v, want %v", gotResult, tt.wantResult)
            }
        })
    }
}

ps :在生成的测试代码中:

  • TestXXX(t *testing.T) 表示基础测试
  • TestXXX(t *testing.B) 表示基准测试

测试

添加测试用例:

package split

import (
    "reflect"
    "testing"
)

func TestSplit(t *testing.T) {
    type args struct {
        s   string
        sep string
    }
    tests := []struct {
        name       string
        args       args
        wantResult []string
    }{
        // TODO: Add test cases. 
        {name: "test1",args: args{s:"a:b:c",sep: ":"},wantResult: []string{"a", "b", "c"}},
        {name: "test2",args: args{s:"a:b:c",sep: ","},wantResult: []string{"a:b:c"}},
        {name: "test3",args: args{s:"abcd",sep: "bc"},wantResult: []string{"a", "d"}},
        {name: "test4",args: args{s:"沙河有沙又有河",sep: "沙"},wantResult: []string{"河有", "又有河"}},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if gotResult := Split(tt.args.s, tt.args.sep); !reflect.DeepEqual(gotResult, tt.wantResult) {
                t.Errorf("Split() = %v, want %v", gotResult, tt.wantResult)
            }
        })
    }
}

go test -v

执行测试: go test -v

$ go test -v 
=== RUN   TestSplit
=== RUN   TestSplit/test1
=== RUN   TestSplit/test2
=== RUN   TestSplit/test3
=== RUN   TestSplit/test4
    split_test.go:27: Split() = [ 河有 又有河], want [河有 又有河]
--- FAIL: TestSplit (0.00s)
    --- PASS: TestSplit/test1 (0.00s)
    --- PASS: TestSplit/test2 (0.00s)
    --- PASS: TestSplit/test3 (0.00s)
    --- FAIL: TestSplit/test4 (0.00s)
FAIL
exit status 1
FAIL    GoTestDemo02/split      0.925s


若只想要测试名称为test4的用例,需要添加“-run”参数,并且写上子测试的名称,关于子测试,官方是这样解释的:

每个子测试和子基准测试都有一个唯一的名称:顶级测试的名称和传递给 Run 的名称的组合,以斜杠分隔,并具有用于消歧的可选尾随序列号。

-run 和 -bench 命令行标志的参数是与测试名称相匹配的非固定的正则表达式。对于具有多个斜杠分隔元素(例如子测试)的测试,该参数本身是斜杠分隔的,其中表达式依次匹配每个名称元素。因为它是非固定的,一个空的表达式匹配任何字符串。例如,使用 "匹配" 表示 "其名称包含":

go test -run ''      # Run 所有测试。
go test -run Foo     # Run 匹配 "Foo" 的顶层测试,例如 "TestFooBar"。
go test -run Foo/A=  # 匹配顶层测试 "Foo",运行其匹配 "A=" 的子测试。
go test -run /A=1    # 运行所有匹配 "A=1" 的子测试。

这里,我们可以这样做:

$ go test -v -run Split/test4
=== RUN   TestSplit
=== RUN   TestSplit/test4
    split_test.go:27: Split() = [ 河有 又有河], want [河有 又有河]
--- FAIL: TestSplit (0.00s)
    --- FAIL: TestSplit/test4 (0.00s)
FAIL
exit status 1
FAIL    GoTestDemo02/split      0.931s

go test -cover:测试覆盖率

$ go test -cover
PASS
coverage: 100.0% of statements
ok      GoTestDemo02/split      0.644s

若想要让以HTML形式展示覆盖率:

$ go test -cover -coverprofile=c.out
PASS
coverage: 100.0% of statements
ok      GoTestDemo02/split      0.849s

$go tool cover -html=c.out

参考链接:

posted @ 2022-01-06 17:17  cosmoswong  阅读(488)  评论(0编辑  收藏  举报