您的位置:

gotest详细阐述

一、gotests

gotests 是一个针对 Go 语言编写的代码自动生成工具。当写测试代码时,由于需要测试的函数或方法较多,且每个测试用例需要按照各种不同的场景编写,使得编写测试用例变得繁琐而耗费时间。因此使用 gotests 可以自动生成函数或方法对应的测试用例代码,提高编写测试用例的效率。

go get -u github.com/cweill/gotests/...

在使用之前需要先安装 gotests 工具:

实例:以下是一个简单的函数 addadd 的测试用例, 运行 gotests 可以自动生成测试用例的代码:

package main

import "fmt"

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

func main() {
    fmt.Println(add(1, 2))
}
go test -v -cover

=== RUN   Test_add
--- PASS: Test_add (0.00s)
PASS
coverage: 100.0% of statements
ok      command-line-arguments  0.191s

二、gotest 上下文

在进行测试时,有时候需要使用到上下文(Context),然而,在测试中,通过测试上下文进行传递的操作比较麻烦。因此,gotest 提供了一种内置的上下文(Context)机制,可以用 gotest.C 对象来实现。

实例:以下是一个函数及测试用例。在测试用例中,可以引用 gotest.C 对象。

package main

import (
    "testing"
)

func Test_calc(t *testing.T) {
    c := context.Background()

    t.Run("test1", func(t *testing.T) { 
        gotest.CB(t) 
        calc(c) 
    })
}

func calc(ctx context.Context) {
    gotest.C.Log("the context is  " ctx)
}

三、gotest pk

在编写测试用例时,有时候需要在一个单独的包内或导入其他包中的函数和变量。使用 go 命令进行测试时,包的名称不会自动成为测试名称,这需要手动指定。因此,gotest 提供了 -include-exclude 等选项,切换使用以包名为测试名称的模式。

实例:以下是包名为 pkg 的测试用例:

package pkg

import "testing"

func Test_add(t *testing.T) {
    if add(1, 2) != 3 { 
        t.Fatal("error")
    }
}

func Test_minus(t *testing.T) {
    if minus(1, 2) != -1 {
        t.Fatal("error")
    }
}

运行测试时,可以使用 -p 参数指定包的名称:

go test -v -p pkg
=== RUN   Test_add
--- PASS: Test_add (0.00s)
=== RUN   Test_minus
--- FAIL: Test_minus (0.00s)
    minus_test.go:9: error
FAIL    command-line-arguments  0.011s
FAIL

四、gotestwaf

使用 go 命令进行测试时,我们可以使用 -run 选项指定要运行的测试用例的名称(pattern)。如果有多个 pattern,需要使用空格分隔。然而,当测试用例较多时,pattern 也可能会很多,使得修改了测试用例名称或新增了测试用例会带来很多麻烦。因此,gotest 提供了一个 -waf 选项,启用自动发现测试用例。

实例:以下是一个带有多个测试用例和 -waf 选项的例子:

func TestAdd1(t *testing.T) {
    if add(1, 2) != 3 { 
        t.Fatal("error")
    }
}

func TestAdd2(t *testing.T) {
    if add(2, 3) != 5 { 
        t.Fatal("error")
    }
}

func TestMinus(t *testing.T) {
    if minus(1, 2) != -1 {
        t.Fatal("error")
    }
}

运行测试:

go test -v -waf
=== RUN   TestAdd1
--- PASS: TestAdd1 (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestMinus
--- FAIL: TestMinus (0.00s)
    minus_test.go:9: error
FAIL    command-line-arguments  0.011s
FAIL

五、gotest围棋

围棋是一种超越国界的传统棋类,在日本、中国、韩国等国家广为流行。因此,对于围棋的编程实现和测试也是必要的,而 gotest 也提供了一个围棋库。

实例:以下是一个围棋棋盘的例子:

package main

import (
    "github.com/gorilla/mux"
    "github.com/sunfmin/gothic"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        gothic.Writer.Write(w, "welcome!")
    })
    go http.ListenAndServe(":8080", r)

    fmt.Println("start server: http://localhost:8080")
}

六、gotest面料

在进行测试时,有时候需要操作面料(fabric),比如 TCP 连接或 HTTP 请求。然而,在测试中进行面料操作比较麻烦,因为可能需要编写一些网络通讯代码。因此,gotest 提供了一种内置的面料对象(fabric),可以对 TCP 或 HTTP 进行模拟或代理。

实例:以下是一个通过 HTTP 请求进行判断的例子:

func TestHttp(t *testing.T) {
    var err error
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "hello, world")
    }))
    defer ts.Close() 

    var resp *http.Response
    resp, err = http.Get(ts.URL) 
    if err != nil {
        t.Fatal(err)
    }

    body, err := ioutil.ReadAll(resp.Body)
    resp.Body.Close()
    if err != nil {
        t.Fatal(err)
    }

    if string(body) != "hello, world\n" {
        t.Fatalf("expect hello, world, but got %q", body)
    }
}

七、gotest功能

除了支持测试用例的编写和执行,gotest 还提供了一些进阶功能。其中包括性能测试、覆盖度分析、基准测试等。

实例1:以下是一个简单的基准测试函数:

func BenchmarkMap(b *testing.B) {
    b.Run("insert", func(b *testing.B) {
        var m map[int]int
        for i := 0; i < b.N; i++ {
            m = make(map[int]int)
            m[i] = i
            _ = m[0]
        }
    })

    b.Run("read", func(b *testing.B) {
        var m = make(map[int]int, b.N)
        for i := 0; i < b.N; i++ {
            m[i] = i
        }
        _ = m[0]
    })
}

实例2:以下是一个覆盖度分析函数:

func Example() {
    Cover()
}

func Cover() {
    path := "/tmp/test.binary" 
    file, err := os.Create(path) 
    if err != nil {
        fmt.Println(err)
        return
    }
    defer file.Close()

    err = cover.StartCover(file)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer cover.StopCover()

    Main()

    cover.WriteCoverageData(file)
}

八、gotest 编译过程

除了提供测试用例的编写和执行外,gotest 还涵盖了测试编译过程的相关知识。通过了解测试编译过程的内容,有助于我们在处理有关测试编译时可能出现的问题时更好地理解和解决。

实例:以下是一个示例程序和编译过程:

package main

import "testing"

func main() {
    t := new(testing.T)
}
go test -c
% ls
command-line-arguments.test   

九、gotest ruc edu cn

gotest 还提供了关于 gotest 项目的 API 接口。

实例:以下是 gotest API 的代码:

package main

import (
    "net/http"
    "net/url"
)

const baseURL = "http://gotest.ruc.edu.cn/api/v1/"

func main() {
    u, err := url.Parse(baseURL)
    if err != nil {
        panic(err)
    }

    u.RawQuery = "key=value"

    client := &http.Client{}

    req, err := http.NewRequest(http.MethodGet, u.String(), nil)
    if err != nil {
        panic(err)
    }

    req.Header.Set("Content-Type", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }

    defer resp.Body.Close()

    fmt.Println(resp.Status)
}

以上代码使用了 Go 的 net/http 包,通过 HTTP 请求向 gotest API 进行访问并获取数据。