go语言中的测试

简介: go语言中的测试

@[toc]

go语言中的测试

测试文件的命名是有一套规则的,通常是某个文件相对应的测试文件,比如app.go的测试文件就是app_test.go

错误测试

错误测试,也是测试中最基础的一种,test首字母要大写,后面的函数(测试谁写谁)首字母也要大写。使用go test命令进行启动。

func TestXxx(t *testing.T){
   
    if xxx {
   
        t.Errorf("xxx")
    }
}

基准测试

所谓基准测试,指的是go语言提供的某个算法或者程序执行一定的次数,然后输出平均的执行时间这个就叫做基准测试

跟test一样B大写,Benchmark 后面的函数首字母也要大写。

func BenchmarkXxx(*testing.B){
   
    // 这里的b.N go会自动提供,次数不一定。
     for i := 0; i < b.N; i++ {
   
        // 这里就是要测试的内容
        rand.Int()
    }
}

如果想在多线程的环境中测试,go给出了一个例子:

func BenchmarkTemplateParallel(b *testing.B) {
   
    templ := template.Must(template.New("test").Parse("Hello, {
   {.}}!"))
    // 这里的 RunParallel函数是关键。
    b.RunParallel(func(pb *testing.PB) {
   
        var buf bytes.Buffer
        for pb.Next() {
   
            buf.Reset()
            templ.Execute(&buf, "World")
        }
    })
}

范例测试

范例测试的意思就是说,运行的结果要跟你提供的例子保持一致

func ExampleHello() {
   
    fmt.Println("hello")
    // Output: hello
}

func ExampleSalutations() {
   
    fmt.Println("hello, and")
    fmt.Println("goodbye")
    // Output:
    // hello, and
    // goodbye
}

这里是有固定形态的,//Output:是固定的用法,后面跟例子输出的结果。

main测试

测试来控制哪些代码在主线程上运行。

func TestMain(m *testing.M){
   
os.Exit(m.Run())
}

子测试

使用`t.Run()`可以进行子测试。
func TestTeardownParallel(t *testing.T) {
   
    // This Run will not return until the parallel tests finish.
    t.Run("group", func(t *testing.T) {
   
        t.Run("Test1", parallelTest1)
        t.Run("Test2", parallelTest2)
        t.Run("Test3", parallelTest3)
    })
    // <tear-down code>
}

关于子测试,命令行里的命令是不一样的:

go test -run ''      # Run all tests.

go test -run Foo     # Run top-level tests matching "Foo", such as "TestFooBar".

go test -run Foo/A=  # For top-level tests matching "Foo", run subtests matching "A=".

go test -run /A=1    # For all top-level tests, run subtests matching "A=1".

跳过测试

如果想跳过某些条件,可以使用t或者b.Skip()方法。

func TestTimeConsuming(t *testing.T) {
   
    if testing.Short() {
   
        t.Skip("skipping test in short mode.")
    }
    ...
}

文件系统测试

这个包是啥意思呢?其实就是帮你模拟了一个文件系统,因为你比如要打开xx文件吧,你不需要单独真的去新建一个,使用这个文件系统的测试,就可以达到这个目的,这个包是testing/fstest

    // 声明一个fstest.MapFs 对象,因为这个对象实现了fs.Fs接口
    //【func (fsys MapFS) Open(name string) (fs.File, error)】
    var ms fstest.MapFS
    // 如果这里不声明ms是这个对象,而是直接就初始化底层类型给ms,
    //下面函数要使用的ms就不是fstest.Mapfs对象,而是map[string]*fstest.MapFile对象
    // 当然你也可以直接不初始化,下面使用的时候显示转化一下即可
    // fstest.MapFs(ms) 即可。


    ms = make(map[string]*fstest.MapFile)
    mf1 := &fstest.MapFile{
   
        Data: []byte("test"),
        Mode: 30,
        ModTime: time.Now(),
        Sys: "12",
    }
    mf2 := &fstest.MapFile{
   
        Data: []byte("test1"),
    }
    // 前面是路径,后面是文件。这是一个模拟。
    ms["a/1"] = mf1
    ms["a/2"] = mf2
    fmt.Println(fstest.TestFS(ms,"a/1","a/2","a/3"))

这里多说一点,go里面的显示类型转化,刚才讲的一般使用的时候,type A int,A类型并不是int,只是它的底层是int,虽然它的一切操作都可以按照int来做,比如

    type A int

     var a A
    //a+1 就等于1,

    // 但是它仍然是A类型不是int,要注意类型转化,只有一个地方go会自动的语法糖,就是return的时候
    func fast()A{
   
            return 1
    }
    // 这里 return的时候进行自动类型判断了,没有把1判断为int,而是判断为A类型了。这属于语法糖。

io测试

io测试包testing/iotest主要是实现了readers和writers,具体我们可以理解为,它实现了很多读取和写入。

黑盒测试

黑盒测试,使用的包是testing/quick

比如一个可以快速得到是否正确的函数

func main(){
   
    f := func() bool{
   
        return 1 == 2
    }
    quick.Check(f,nil)
}

首先,对于我们来说,qucik.Check()是这个盒子的外壳,我们只能看到它,f我们是看不到的,所以我们可以通过check得到f的返回bool结果。

下面这个函数就是可以黑盒看f f1 是否是一致的。

func main(){
   
    f := func() bool{
   
        return true
    }

    f1 := func()bool {
   
        return false
    }

    quick.CheckEqual(f,f1,nil)
}

http测试

http测试,意思就是当你需要一个服务的时候,不需要自己再写一个http服务,你只需要net/http/httptest包即可。

这个包大致可以分为三个内容

  1. request,请求
    注意此包并不是客户端的请求,这是服务端的请求。【客户端用postman】
    func NewRequest(method, target string, body io.Reader) *http.Request
    

目标是RFC 7230“请求目标”:它可以是路径或绝对URL。如果目标是绝对URL,则使用URL中的主机名。否则,将使用“ example.com”。

method 空是get

  1. response,响应
    这个包就是生成一个响应。
    func NewRecorder() *ResponseRecorder
    
  2. server,服务
    服务器是侦听本地接口上系统选择的端口的HTTP服务器,用于端到端HTTP测试。
// 在这段代码中,第一段是一个server,下面是一个客户端get请求。所以上面哪个server监听了本地的请求。
func main() {
   
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   
        fmt.Fprintln(w, "Hello, client")
    }))
    defer ts.Close()

    res, err := http.Get(ts.URL)
    if err != nil {
   
        log.Fatal(err)
    }
    greeting, err := io.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
   
        log.Fatal(err)
    }

    fmt.Printf("%s", greeting)
}

性能分析

net/http/pprof 包提供了例如gc,内存,cpu等数据的性能分析包。

如果要使用这个功能,需要写入这个import _ "net/http/pprof"

以及将下面代码加入

go func() {
   
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

新开一个go的groutine,然后来进行性能分析。

https://golang.org/pkg/net/http/pprof/

go tool pprof -http=:6062 http://localhost:6060/debug/pprof/block

go tool pprof -http=:6062 http://localhost:6060/debug/pprof/goroutine

go tool pprof -http=:6062 http://localhost:6060/debug/pprof/cpus

使用这个命令,可以把数据的分析,使用浏览器打开,http跟的端口,是自己设定的,后面的是分析的具体参数,比如/block /heap等。下面有个列表,最前面就是这些命令。

runtime/pprof
pprof的具体实现,所有类型的代码都可以使用。如果不是Web应用程序,建议使用该包。

类型 描述 备注
allocs 内存分配情况的采样信息 可以用浏览器打开,但可读性不高
blocks 阻塞操作情况的采样信息 可以用浏览器打开,但可读性不高
cmdline 显示程序启动命令及参数 可以用浏览器打开,但可读性不高
goroutine 当前所有协程的堆栈信息 可以用浏览器打开,但可读性不高
heap 堆上内存使用情况的采样信息 可以用浏览器打开,但可读性不高
mutex 锁争用情况的采样信息 可以用浏览器打开,但可读性不高
profile CPU 占用情况的采样信息 浏览器打开会下载文件
threadcreate 系统线程创建情况的采样信息 可以用浏览器打开,但可读性不高
trace 程序运行跟踪信息 浏览器打开会下载文件

http请求跟踪测试

net/http/trace包提供了监听http请求的各个过程的功能,我们来看一个例子

func main() {
   
    // 这里有一个新的request
    req, _ := http.NewRequest("GET", "http://example.com", nil)
    // 这里,有两个参数被监听
    trace := &httptrace.ClientTrace{
   
        GotConn: func(connInfo httptrace.GotConnInfo) {
   
            fmt.Printf("Got Conn: %+v\n", connInfo)
        },
        DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
   
            fmt.Printf("DNS Info: %+v\n", dnsInfo)
        },
    }
    // 将钩子放入这个http的请求之内,实现监听的效果。
    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
    _, err := http.DefaultTransport.RoundTrip(req)
    if err != nil {
   
        log.Fatal(err)
    }
}
目录
相关文章
|
2月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
200 1
|
10月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
10月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
4月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
296 1
|
4月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
396 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
260 0
|
4月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
229 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
331 0
|
4月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
4月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。

热门文章

最新文章