go语言中的测试

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
2. response,响应
这个包就是生成一个响应。

func NewRecorder() *ResponseRecorder
  1. 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锁争用情况的采样信息可以用浏览器打开,但可读性不高
profileCPU 占用情况的采样信息浏览器打开会下载文件
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)
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值