Go语言系列(十二):测试

测试

  • DEBUG,多Testing
  • go语言采用表格驱动测试
    • 分离的测试数据和测试逻辑
    • 明确的出错信息
    • 可以部分失败
    • go语言的语法使得我们更容易实践表格驱动测试
// 如果要测试add函数,那么文件名就叫做add_test.go
// 测试方法名字就叫做TestAdd
package main

import "testing"

func add(a, b int) int {
	return a + b
}
func TestAdd(t *testing.T) {

	tests := []struct{ a, b, c int }{
		{3, 4, 7},
		{1, 2, 3},
		{4, 5, 1}, //模拟出错
		{1, 1, 1}, // 模拟出错
	}

	for _, tt := range tests {
		if actual := add(tt.a, tt.b); actual != tt.c {
			t.Errorf("%d + %d got %d ;expected %d ", tt.a, tt.b, tt.c, actual)
		}
	}
}

  • 控制台
GOROOT=/usr/local/go #gosetup
GOPATH=/Users/xiao_xiaoxiao/go #gosetup
/usr/local/go/bin/go test -c -o /private/var/folders/db/mpycn34j5534hjnxy33y6h9m0000gn/T/___TestAdd_in_learn2_testing learn2/testing #gosetup
/usr/local/go/bin/go tool test2json -t /private/var/folders/db/mpycn34j5534hjnxy33y6h9m0000gn/T/___TestAdd_in_learn2_testing -test.v -test.run ^TestAdd$ #gosetup
=== RUN   TestAdd
    TestAdd: add_test.go:19: 4 + 5 got 1 ;expected 9 
    TestAdd: add_test.go:19: 1 + 1 got 1 ;expected 2 
--- FAIL: TestAdd (0.00s)
FAIL
用命令行测试
  • 在当前目录下使用go test命令
    不通过
    在这里插入图片描述
    通过
    在这里插入图片描述

代码覆盖率

  • go语言可以检测代码覆盖率
    在这里插入图片描述
    在这里插入图片描述
    这个项目里面的代码都会统计覆盖率

在这里插入图片描述

用命令行操作
  • go test -coverprofile=c.out 生成文件

  • go tool cover -html=c.out 页面观看覆盖率
    在这里插入图片描述

  • 注意: test文件要和逻辑代码在同一个包中 不然显示不出来

性能测试


// BenchmarkXxx testing.B
func BenchmarkAdd(b *testing.B) {
	a, j, c := 1, 2, 3 //一般性能测试选择最复杂的那个用例,

	// 如果在这里做测试用的数据的生成,不想把这个时间加进去,可以在生成数据之后reset一下时间
	b.ResetTimer()
	
	for i := 0; i < b.N; i++ { //性能测试一般循环多次,具体不用我们定,用b.N系统自动帮我们确定多少次
		actual := Add(a, j)
		if actual != c {
			b.Errorf("%d + %d got %d ;expected %d ", a, j, c, actual)

		}
	}
}

控制台

GOROOT=/usr/local/go #gosetup
GOPATH=/Users/xiao_xiaoxiao/go #gosetup
/usr/local/go/bin/go test -c -o /private/var/folders/db/mpycn34j5534hjnxy33y6h9m0000gn/T/___BenchmarkAdd_in_learn2_testing learn2/testing #gosetup
/private/var/folders/db/mpycn34j5534hjnxy33y6h9m0000gn/T/___BenchmarkAdd_in_learn2_testing -test.v -test.bench ^BenchmarkAdd$ -test.run ^$ #gosetup
goos: darwin
goarch: amd64
pkg: learn2/testing
BenchmarkAdd
# 100000000次    每次操作  0.512 ns
BenchmarkAdd-4   	1000000000	         0.512 ns/op
PASS
用命令行

go test -bench .

性能调优

在这里插入图片描述

  • go test -bench . -cpuprofile=cpu.out生成二进制文件
  • 用pprof查看这个二进制文件go tool pprof cpu.out进入pprof环境
  • 进入pprof环境之后,使用web命令生成图(要先安装graphviz工具)
  • 这张图会告诉你时间消耗在哪个地方,箭头越粗,方框越大越耗时
    (大概长这样,我的用例太简单了,所以截图了其他的用例的图)
    在这里插入图片描述
  • 然后通过看这张图,看哪里可以优化,优化完再次运行,然后不断优化到满意为止

http测试

  • 分为2种,一种是测试这个函数是否正确,虚构http请求的requestresponse,然后测试函数对各种返回是否正常,第二种是测试服务器是否正常,构造一个server,然后通过通信,看看是否正常
package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
)

// 测试errWrapper
// 入参是appHandler  :::type appHandler func(writer http.ResponseWriter, request *http.Request) error
// func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
// }

// ******************* 入参构造 ***********************//
// 模拟抛出错误
func errPanic(_ http.ResponseWriter, _ *http.Request) error {
	panic(123)
}

type testingUserError string

func (e testingUserError) Error() string {
	return e.Message()
}

func (e testingUserError) Message() string {
	return string(e)
}

// 模拟用户错误
func errUserError(_ http.ResponseWriter, _ *http.Request) error {
	return testingUserError("user error")
}

//模拟。。。
func errNotFound(_ http.ResponseWriter, _ *http.Request) error {
	return os.ErrNotExist
}

func errNoPermission(_ http.ResponseWriter, _ *http.Request) error {
	return os.ErrPermission
}

func errUnknown(_ http.ResponseWriter, _ *http.Request) error {
	return errors.New("unknown error")
}

// 没有错误
func noError(writer http.ResponseWriter, _ *http.Request) error {
	fmt.Fprintln(writer, "no error")
	return nil
}

// 这个是 测试用例
var tests = []struct {
	h appHandler // 入参
	// 返回的信息
	code    int
	message string
}{
	{errPanic, 500, "Internal Server Error"},
	{errUserError, 400, "user error"},
	{errNotFound, 404, "Not Found"},
	{errNoPermission, 403, "Forbidden"},
	{errUnknown, 500, "Internal Server Error"},
	{noError, 200, "no error"},
}

//测试errWrapper
// 只是测试errWrapper这个函数
func TestErrWrapper(t *testing.T) {
	for _, tt := range tests {
		f := errWrapper(tt.h) //入参
		// httptest 可以虚构request 和 response
		// response  request 是 指针类型
		response := httptest.NewRecorder()
		request := httptest.NewRequest(http.MethodGet, "http://www.imooc.com", nil)
		f(response, request) // 执行
		verifyResponse(response.Result(), tt.code, tt.message, t)
	}
}

// 测试整个服务器是否正常,这个是真的发请求,
func TestErrWrapperInServer(t *testing.T) {
	for _, tt := range tests {
		f := errWrapper(tt.h)
		// 发请求 构造一个server 
		server := httptest.NewServer(
			http.HandlerFunc(f)) // 传入处理函数
		resp, _ := http.Get(server.URL)
		verifyResponse(resp, tt.code, tt.message, t)
	}
}

// 判断 是否正确
func verifyResponse(resp *http.Response, expectedCode int, expectedMsg string, t *testing.T) {
	b, _ := ioutil.ReadAll(resp.Body)
	body := strings.Trim(string(b), "\n")
	if resp.StatusCode != expectedCode ||
		body != expectedMsg {
		t.Errorf("expect (%d, %s); "+
			"got (%d, %s)",
			expectedCode, expectedMsg,
			resp.StatusCode, body)
	}
}

生成文档和示例代码

文档
  • go语言的文档生成用godoc

godoc命令要自己安装

  • 第一种:直接在命令行查看
go doc # 显示struct结构 和引入哪些包
# package queue // import "imooc.com/ccmouse/learngo/lang/queue"
# type Queue []int

go doc Push #方法
#package queue // import "."
# func (q *Queue) Push(v int)
#     Pushes the element into the queue.

go doc Queue
# package queue // import "."
#type Queue []int
#    A FIFO queue.

#func (q *Queue) IsEmpty() bool
#func (q *Queue) Pop() int
#func (q *Queue) Push(v int)

go help doc
  • 在页面中看
godoc -http :8080
注释
  • go文档的注释是可以随便写的
package queue

// A FIFO queue.
type Queue []int

// Pushes the element into the queue. 注释会记录下来
// 		e.g. q.Push(123)   会缩进而且用框框框起来
func (q *Queue) Push(v int) {
	*q = append(*q, v)
}

// Pops element from head.
func (q *Queue) Pop() int {
	head := (*q)[0]
	*q = (*q)[1:]
	return head
}

// Returns if the queue is empty or not.
func (q *Queue) IsEmpty() bool {
	return len(*q) == 0
}

在这里插入图片描述

example
func ExampleQueue_Pop() {
	q := Queue{1}
	q.Push(2)
	q.Push(3)
	fmt.Println(q.Pop())
	fmt.Println(q.Pop())
	fmt.Println(q.IsEmpty())

	fmt.Println(q.Pop())
	fmt.Println(q.IsEmpty())

	// Output: 
	// 1
	// 2
	// false
	// 3
	// true
}

格式正确的话是可以运行的,在代码中不要有多余的注释,不然运行不起来的
在这里插入图片描述
-生成文件
在这里插入图片描述

总结
  • 用注释写文档
  • 在测试中加入Example
  • go doc/godoc来查看/生成文档
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值