Golang 学习笔记② 单元测试

使用Golang的标准包testing可以创建Golang的单元测试。

验证环境的目录结构

golang
├main.go
└person
 ├person.go
 └person_test.go

在VSCode中进行单元测试的方法

在想要测试的方法上打开上下文菜单,选择“生成函数单元测试”,即可生成测试代码。
testing会生成一个名为{待测试源文件名}_test.go的文件。

ezgif.com-video-to-gif (5).gif
package main

import (
    "fmt"
    "./person"
)

func main() {
    fmt.Println("start")
    person.InitPerson()

}
package person

import "fmt"

// Person Recording Persons Score & rank.
type Person struct {
    name    string
    english int
    rank    string
}

// InitPerson doing Initialize Person.
func InitPerson() {
    Bob := Person{"Bob", 60, ""}
    Bob.rank = Score(Bob)
    fmt.Printf("Name:%v\n", Bob.name)
    fmt.Printf("Score:%v\n", Bob.english)
    fmt.Printf("rank:%v\n", Bob.rank)
}

// Score Return rank by score.
func Score(p Person) string {
    if p.english > 80 {
        return "A"
    } else if p.english > 60 {
        return "B"
    } else {
        return "C"
    }
}

当对person.go中的Score方法进行测试时,将生成下面的测试代码。

package person

import (
    "testing"
)
func TestScore(t *testing.T) {
    type args struct {
        p Person
    }
    tests := []struct {
        name string
        args args
        want string
    }{
        // TODO: Add test cases.
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Score(tt.args.p); got != tt.want {
                t.Errorf("Score() = %v, want %v", got, tt.want)
            }
        })
    }
}

不使用骨架,可以将测试值传递给生成的代码的结构体,并执行测试,
但是这次我们创建了以下的测试代码,而不使用骨架。

package person

import (
    "testing"
)

func TestScore_1(t *testing.T) {
    p := Person{"Bob", 60, ""}
    actual := Score(p)
    expected := "C"
    if actual != expected {
        t.Errorf("got %v want %v", actual, expected)
    }
}

在VSCode上,当执行上面显示在方法顶部的运行测试功能时,可以按方法为单位执行测试。执行后,以下结果将在终端中输出。

Running tool: /usr/local/go/bin/go test -timeout 30s -run ^(TestScore_1)$

PASS
ok      _/Users/username/golang/golang/person   0.010s
Success: Tests passed.

另外,在存储测试代码的目录中执行”go test .”,可以执行该目录中的所有测试。
我刚刚在代码中添加了两个新测试案例。
为了确认失败时的操作,我设置了TestScore_3作为一个NG案例。

package person

import (
    "testing"
)

func TestScore_1(t *testing.T) {
    p := Person{"Bob", 90, ""}
    actual := Score(p)
    expected := "A"
    if actual != expected {
        t.Errorf("got %v want %v", actual, expected)
    }
}

func TestScore_2(t *testing.T) {
    p := Person{"Bob", 80, ""}
    actual := Score(p)
    expected := "B"
    if actual != expected {
        t.Errorf("got %v want %v", actual, expected)
    }
}

//NG case
func TestScore_3(t *testing.T) {
    p := Person{"Bob", 60, ""}
    actual := Score(p)
    expected := "B"
    if actual != expected {
        t.Errorf("got %v want %v", actual, expected)
    }
}

如果测试失败,则无法获得正常的结果,并将显示出引起失败的源代码部分和设定的错误信息在终端上。
一旦发生一个错误,后续的代码将不再执行。

$ go test .
--- FAIL: TestScore_3 (0.00s)
    person_test.go:31: got C want B
FAIL
FAIL    _/Users/username/golang/golang/person 0.006s
FAIL

获取报道

通过使用cover选项,可以获得代码覆盖率。

go test . -cover
ok      _/Users/username/golang/golang/person 0.011s  coverage: 50.0% of statements

另外,还可以将覆盖率作为HTML输出。
通过使用test的-coverprofile选项,将覆盖率文件输出到文件中,
然后再使用go tool cover将输出的文件转换为HTML文件。

$go test -coverprofile=cover.out ./
ok      _/Users/username/golang/golang/person 0.007s  coverage: 50.0% of statements
$ go tool cover -html=cover.out -o cover.html

将覆盖范围用HTML显示如下:

image.png
bannerAds