Go语言编程思想4——测试与性能调优

2023-11-12

Go语言编程思想4——测试与性能调优

Debugging Sucks! Testing Rocks!
多做测试,少做调试

Go语言使用表格驱动测试

一、传统测试

正确结果在前,函数结果在后,判断是否相等

在这里插入图片描述

  • 测试逻辑和测试数据混在一起
  • 出错信息不明确
  • 一旦一个数据出错测试全部结束

二、表格驱动测试

将测试数据写在struct中,a + b = c

卸载for循环中判断add(a,b)是否等于c,若不等于再进一步处理

测试文件命名:测试的东西_test(若不按照标准命名则无法执行测试函数),本例文件命名为Triangle_test

测试函数命名需要为Test+测试名称

在这里插入图片描述

  • 分离的测试数据和测试逻辑
  • 明确的出错信息
  • 可以部分失败
  • go语言的语法使得我们更易实践表格驱动测试

func calcTriangle(a, b int) int {
	var c int
	c = int(math.Sqrt(float64(a*a + b*b)))
	return c
}

func TestTriangle(t *testing.T) {
	tests := []struct{ a, b, c int }{
		{3, 4, 5},
		{5, 12, 13},
		{8, 15, 17},
		{12, 35, 37},
		{30000, 40000, 50000},
	}

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

命令行中运行测试,进入test文件目录,运行go test .
在这里插入图片描述

三、代码覆盖率

查看测试代码的代码覆盖率

运行测试函数:run ‘…’ with Coverage
在这里插入图片描述

被测试的代码中,绿色的是覆盖到的,红色是没有覆盖到的,点击绿色部分可以看到覆盖了多少次

在这里插入图片描述

命令行
go test -coverprofile c.out
go tool cover -html c.out
在这里插入图片描述

四、性能测试

在Triangle_test文件中继续创建下列函数

注意函数命名需要为Benchmark+测试名称

b.N为测试次数

func BenchmarkTriangle(b *testing.B) {
	aa := 30000
	bb := 40000
	cc := 50000
	for i := 0; i < b.N; i++ {
		actual := calcTriangle(aa, bb)
		if actual != cc {
			b.Errorf("calcTriangle(%d,%d);"+
				"got %d;expected %d",
				aa, bb, actual, cc)
		}
	}
}

结果:在这里插入图片描述

命令行 go test -bench .
在这里插入图片描述

五、pprof性能调优

命令行命令:

  1. go test -bench . -cpuprofile cpu.out 获得cpu性能的日志文件cpu.out
  2. go tool pprof cpu.out 查看日志文件
  3. 执行完pprof后会进入命令行,再执行web命令可以进入web页面可视化日志文件,这里需要先安装Graphviz,链接放在下面直接下载安装即可。
    Graphviz

可视化结果:

方框越大,箭头越粗,耗时越长
在这里插入图片描述

优化map的方法

map是哈希表实现会有判重等操作
可以使用空间换时间
a:=make([]int,0xffff)
假设中文字符最大就是0xFFFF,这里开一个0xFFFF大小的数组可以存储所有字符
使用:a[‘e’]=1(实质:a[0x65]=1);a[‘课’]=1(实质:a[0x8BFE]=1)

性能调优的步骤

  1. -cpuprofile:获取性能数据
  2. go tool pprof:查看性能数据(web可视化)
  3. 分析慢在哪里(哪个框最大)
  4. 优化代码
  5. 再用-cpuprofile获取性能数据,查看优化结果,继续优化

六、http测试

两种方法

  • 通过使用假的Request/Response
  • 通过起服务器

测试的函数参考之前笔记7中的服务器统一错误处理


func errPanic(writer http.ResponseWriter,
	request *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(writer http.ResponseWriter,
	request *http.Request) error {
	return testingUserError("user error")
}

func errNotFound(writer http.ResponseWriter,
	request *http.Request) error {
	return os.ErrNotExist
}
func errNotPermission(writer http.ResponseWriter,
	request *http.Request) error {
	return os.ErrPermission
}
func errUnknown(writer http.ResponseWriter,
	request *http.Request) error {
	return errors.New("unknown error")
}
func noError(writer http.ResponseWriter,
	request *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"},
	{errNotPermission, 403, "Forbidden"},
	{errUnknown, 500, "Internal Server Error"},
	{noError, 200, "no error"},
}

//用假的request,response,速度快
func TestErrWrapper(t *testing.T) {
	for _, tt := range tests {
		f := errWrapper(tt.h)
		response := httptest.NewRecorder()
		request := httptest.NewRequest(
			http.MethodGet, "http://www.imooc.com", nil)
		f(response, request)
		verifyResponse(response.Result(), tt.code, tt.message, t)
	}
}

//真正起一个server,测试力度更大
func TestErrWrapperInServer(t *testing.T) {
	for _, tt := range tests {
		f := errWrapper(tt.h)
		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, expectMsg string, t *testing.T) {
	b, _ := ioutil.ReadAll(resp.Body)
	body := strings.Trim(string(b), "\n")
	if resp.StatusCode != expectedCode || body != expectMsg {
		t.Errorf("expected(%d,%s);"+
			"got(%d,%s)",
			expectedCode, expectMsg,
			resp.StatusCode, body)
	}
}

七、生成文档

用注释写文档
在测试中加入Example
使用go doc/godoc 来查看/生成文档

godoc -http :6060生成文档,通过 http://localhost:6060 访问

注释


// An 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
}

示例代码:
也可以当做测试来做

函数命名为ExampleQueue_+函数名

注释为标准答案,先写Output,格式必须严格一致

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可以看作是特别的test,可以执行函数进行测试(注释为想要得到的结果),同时也可以生成文档的example
若将注释中的false删掉e,执行函数得到以下结果
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言编程思想4——测试与性能调优 的相关文章

随机推荐

  • centOS 6 服务管理与服务脚本

    服务管理与服务脚本 linux服务 服务管理与服务脚本 linux服务 服务启动过程详解 chkconfig命令 非独立服务与xinetd进程 一个特殊的服务脚本 服务启动过程详解 在开机启动过程中 我们计算机的各种服务也会按照配置信息启动
  • python 数据标准化

    def datastandard from sklearn import preprocessing import numpy as np x np array 1 1 2 2 0 0 0 1 1 print 原始数据为 n x print
  • 交换机上抓包

    1 常用交换机抓包方式 华为 华三 锐捷交换机一般使用packet capture命令可以进行抓包 Arista交换机通过在bash下 使用linux命令tcpdump进行抓包 Cisco nexus 抓包使用ethanalyze命令 具体
  • AS400银行核心系统开发中的技术总结--数据字典和枚举值

    数据字典和枚举值 在核心系统应用开发中 数据字典有举足轻重的作用 数据字典是对系统中所有字段的归纳抽象 需要规范同类字段的类型长度 方便定义和修改 但是 在过去的核心系统中 数据字典的理解往往也会有失误 常见的错误方法 是试图穷举定义所有可
  • Flink Client 使用技巧和心得(Flink on Zeppelin)

    Flink 链接Kafka 先建立catalog CREATE CATALOG flink hive WITH type hive default database imods hive conf dir home admin flink
  • 八个维度讲解秒杀系统架构分析与实战

    路人 Java充电社 2022 09 06 08 06 发表于上海 收录于合集 java充电社263个 大家好 我是路人 更多优质文章见个人博客 http itsoku com Java充电社 Java充电社 专注分享Java技术干货 包括
  • 最小熵原理

    种草很好的博文 苏剑林 2018 Apr 18 最小熵原理 一 无监督学习的原理 Blog post Retrieved from https spaces ac cn archives 5448 苏剑林 2018 Apr 24 最小熵原理
  • scrapy框架的使用

    1 什么是scrapy框架 文档地址 http scrapy chs readthedocs io zh CN 1 0 intro overview html 这个详细的文档地址 大家可以保存一下 之前的文章中也有一些链接大家可以保存下来方
  • 云计算中的存储基础知识

    物理存储方式 云计算中的三辆马车 计算 网络 存储 硬盘分为两种型态 机械硬盘 HDD 和固态硬盘 SSD 物理磁盘类型 SATA盘 串口硬盘 常用于个人电脑 物理磁盘类型 SAS盘 常用于服务器 物理磁盘类型 NL SAS盘 采用SAS磁
  • Doris-查询(三)

    目录 1 查询设置 1 1 增大内存 1 2 修改超时时间 1 3 查询重试和高可用 1 3 1 代码方式 1 3 2 JDBC Connector 1 3 3 ProxySQL 方式 2 简单查询 3 Join查询 3 1 Broadca
  • PyQT5播放音频

    最近自己写的一个软件需要在持续监测T box的信号强度值时 领导提出在信号低于阈值时给出警报或指示 之前的想法是在软件界面上加一个指示灯 但这样还是需要Tester去盯着屏幕 这样不友好 所以索性在通过声音的方式给出警示 这样就不用一直盯着
  • 基于sklearn的特征选择方法

    1 特征选择 我们主要关心以下几个问题 1 特征差异性 也就是一列特征值若几乎没有什么变化 那么这个特征对模型并没有什么作用 2 相关性大小 也就是该维特征与target的相互作用有多大 2 过滤法 1 方差判别 给定阈值 排除那些方差低于
  • GZ-2022034 物联网技术应用赛项赛题(Windows系统运行维护)

    任务书1 使用过程发现局域网内网络设备无法获取到有效IP 请配置DHCP服务分配的IP从172 16 工位号 150开始至172 16 工位号 200结束 并启用服务 使用路由器配置DHCP 在工作站计算机中使用DOS窗口测试服务器计算机8
  • exure9 秘钥_AxureRP9.0秘钥(持续更新)

    Axure RP 9 0 0 3717 3719 正式版 Axure Enterprise Edition Licensee Freecrackdownload com KEY 5vYpJgQZ431X G5kp6jpOO8Vi3TySCB
  • 嵌入式系统之linux系统编程---16 守护进程

    1 什么是守护进程 守护进程 守护进程运行在后台 不跟任何控制终端关联 2 怎么创建一个守护进程 有两个基本要求 a 守护进程必须作为 init 进程的子进程 b 守护进程不跟控制终端交互 创建守护进程的步骤 1 使用 fork 函数创建一
  • 百度云的sugar大屏模板1

    1 企业实时销售数据1 2 企业实时销售数据2 3 电商618大数据 4 实时数据分析 5 某平台智能监控系统
  • Spring WebFlux编写响应式Controller接口

    文章目录 一 基本概念 1 什么是响应式编程 2 响应式流中的各个角色和关系 二 Reactor简介 1 Mono与Flux 三 Spring WebFlux 1 简介 2 构建响应式Controller 3 使用函数式编程模型编写API
  • docker--扩展学习-网络--命令--15

    docker 扩展学习 网络 命令 15 1 创建网络 1 1 简单创建容器 创建 docker network create net111 查看 docker network inspect net111 1 2 指定参数创建容器 创建
  • rabbitmq基础1——消息中间件概念、Rabbitmq的发展起源和基本组件的作用流程

    文章目录 一 消息中间件 1 1 概念 1 2 作用 1 2 1 消息队列持久化 1 2 2 消息队列分发策略 1 2 3 消息队列的高可用和高可靠 1 2 3 1 一主多从共享集群 1 2 3 2 一主多从同步集群 1 2 3 3 多主多
  • Go语言编程思想4——测试与性能调优

    Go语言编程思想4 测试与性能调优 Debugging Sucks Testing Rocks 多做测试 少做调试 Go语言使用表格驱动测试 一 传统测试 正确结果在前 函数结果在后 判断是否相等 测试逻辑和测试数据混在一起 出错信息不明确