Go语言的单元测试与基准测试详解
文章目录
- 单元测试
- 基准测试
单元测试
以一个加法函数为例,对其进行单元测试。
首先编写add.go文件:
//add.go
package mainfunc add(a, b int) int {return a + b
}
其次编写add_test.go文件,在go语言中,测试文件均已_test结尾,这里只需要在被测试的文件后加上_test即可。并且测试文件与要被测试的文件需要放在同一个包中,并不像Java那样需要将所有的测试文件放在一个专门的测试文件夹里面,例如我将这两个文件都放在main包下:
package mainimport ("fmt""testing"
)//测试函数需要以Test开头
func TestAdd(t *testing.T) {fmt.Println("Running short test")res := add(1, 2)if res != 3 {t.Errorf("add(1,2) should be 3, got %d", res)}
}
cd到测试文件的目录,执行测试命令go test:
以下是运行结果:
(base) PS F:\GolandProjects\GoProject1\main> go test
Running short test
PASS
ok GoProject1/main 0.489s
如果想在测试中跳过那些需要耗时比较长的测试,可以做以下处理:
package mainimport ("fmt""testing"
)func TestAdd(t *testing.T) {fmt.Println("Running short test")res := add(1, 2)if res != 3 {t.Errorf("add(1,2) should be 3, got %d", res)}
}func TestAdd2(t *testing.T) {if testing.Short() {fmt.Println("Skipping long test")//短测试模式就跳过该测试t.Skip("Skipping long test")}fmt.Println("Running long test")res := add(5, 6)if res != 11 {t.Errorf("add(5,6) should be 11, got %d", res)}
}
在运行时指执行短测试,只需要执行go test -short:
(base) PS F:\GolandProjects\GoProject1\main> go test -short
Running short test
Skipping long test
PASS
ok GoProject1/main 0.448s
我们发现跳过了第二个测试,也就是测试函数TestAdd2。
当然如果还是执行go test命令,则两个测试都将会运行:
(base) PS F:\GolandProjects\GoProject1\main> go test
Running short test
Running long test
PASS
ok GoProject1/main 0.417s
如果想要同时测试很多条数据,可以按如下的方式处理,而不需要写很多的函数:
func TestAdd3(t *testing.T) {var dataset = []struct {a, b, expected int}{{1, 2, 3},{5, 6, 11},{10, 20, 30},{100, 200, 300},}for _, d := range dataset {res := add(d.a, d.b)if res != d.expected {t.Errorf("add(%d,%d) should be %d, got %d", d.a, d.b, d.expected, res)}}
}
这里我们用go test -v测试一下:
(base) PS F:\GolandProjects\GoProject1\main> go test -v
=== RUN TestAdd
Running short test
--- PASS: TestAdd (0.00s)
=== RUN TestAdd2
Running long test
--- PASS: TestAdd2 (0.00s)
=== RUN TestAdd3
--- PASS: TestAdd3 (0.00s)
PASS
ok GoProject1/main 0.408s
go test 用于运行测试并显示简洁的结果,而 go test -v 用于以详细模式运行测试并提供更多的输出信息,有助于更深入地了解测试的运行情况。通常,在开发和调试过程中,使用 -v 标志是很有帮助的,但在持续集成和自动化测试中,可能更倾向于使用简洁的 go test,以便更容易解释测试结果。
基准测试
性能表现需要实际数据衡量,Go语言提供了支持基准性能测试的benchmark工具。基准测试用于确定一段代码的执行速度和性能,并可以用来优化和改进代码。
以编写斐波那契函数为例:
//fib.go
package mainfunc Fib(n int) int {if n < 2 {return n}return Fib(n-1) + Fib(n-2)
}
//fib_test.go
package mainimport ("testing"
)func BenchmarkFib10(b *testing.B) {for i := 0; i < b.N; i++ {Fib(10)}
}
benchmark 和普通的单元测试用例一样,都位于 _test.go 文件中。
函数名以 Benchmark 开头,参数是 b *testing.B。和普通的单元测试用例很像,单元测试函数名以 Test 开头,参数是t *testing.T。使用 b.N 控制循环次数:b.N 是基准测试的循环次数,它会根据不同的运行情况自动调整,以保证结果的可比性。
- 运行当前 package 内的用例:
go test . - 运行子 package 内的用例:
go test ./<package name> - 如果想递归测试当前目录下的所有的 package:
go test ./...
go test 命令默认不运行 benchmark 用例的,如果我们想运行 benchmark 用例,需要加上 -bench 参数。例如:
$ go test -bench .
goos: windows
goarch: amd64
pkg: GoProject1
cpu: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
BenchmarkFib10-16 5496252 212.5 ns/op
PASS
ok GoProject1 1.454s
goos: windows:这行显示运行基准测试的操作系统,此处为 Windows。goarch: amd64:这行显示运行基准测试的机器架构,此处为 64 位 AMD 架构。pkg: GoProject1:这行显示包含基准测试代码的包名,此处为 “GoProject1”。cpu: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz:这行显示运行基准测试的机器 CPU 信息,包括 CPU 型号和时钟频率。PASS:这行表示所有的测试,包括基准测试,都已成功通过。ok GoProject1 1.454s:这行显示所有测试,包括基准测试,的整体执行时间。在这种情况下,整个测试套件执行时间大约为 1.454 秒。BenchmarkFib10-16是测试函数名,-16表示GOMAXPROCS的值为16,GOMAXPROCS 1.5版本后,默认值为CPU核数 。5496252表示一共执行5496252次,即b.N的值。212.5 ns/op表示每次执行花费212.5ns。
再举一个比较详细的例子,比较不同字符串处理方式的性能:
func Plus(n int, str string) string {s := ""for i := 0; i < n; i++ {s += str}return s
}func StrBuilder(n int, str string) string {var builder strings.Builderfor i := 0; i < n; i++ {builder.WriteString(str)}return builder.String()
}func ByteBuffer(n int, str string) string {buf := new(bytes.Buffer)for i := 0; i < n; i++ {buf.WriteString(str)}return buf.String()
}func PreStrBuilder(n int, str string) string {var builder strings.Builderbuilder.Grow(n * len(str))for i := 0; i < n; i++ {builder.WriteString(str)}return builder.String()
}
func PreStrByteBuffer(n int, str string) string {buf := new(bytes.Buffer)buf.Grow(n * len(str))for i := 0; i < n; i++ {buf.WriteString(str)}return buf.String()
}
基准测试函数:
func BenchmarkPlus(b *testing.B) {for i := 0; i < b.N; i++ {Plus(100000, "wxy")}
}func BenchmarkStrBuilder(b *testing.B) {for i := 0; i < b.N; i++ {StrBuilder(100000, "wxy")}
}func BenchmarkByteBuffer(b *testing.B) {for i := 0; i < b.N; i++ {ByteBuffer(100000, "wxy")}
}func BenchmarkPreStrBuilder(b *testing.B) {for i := 0; i < b.N; i++ {PreStrBuilder(100000, "wxy")}
}func BenchmarkPreByteBuffer(b *testing.B) {for i := 0; i < b.N; i++ {PreStrByteBuffer(100000, "wxy")}
}
以下是运行结果:
$ go test -bench .
goos: windows
goarch: amd64
pkg: GoProject1
cpu: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
BenchmarkPlus-16 1 1126084200 ns/op
BenchmarkStrBuilder-16 3982 284773 ns/op
BenchmarkByteBuffer-16 2947 485091 ns/op
BenchmarkPreStrBuilder-16 4771 278961 ns/op
BenchmarkPreByteBuffer-16 3310 364676 ns/op
PASS
ok GoProject1 6.457s
- 使用
+拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Builder更快 - 字符串在Go语言中是不可变类型,占用内存大小是固定的
- 使用
+每次都会重新分配内存 strings.Builder,bytes.Buffer底层都是[]byte数组。内存扩容策略,不需要每次拼接重新分配内存- 预分配内存后,
strings.Builder,bytes.Buffer性能都有所提升
相关文章:
Go语言的单元测试与基准测试详解
文章目录 单元测试基准测试 单元测试 以一个加法函数为例,对其进行单元测试。 首先编写add.go文件: //add.go package mainfunc add(a, b int) int {return a b }其次编写add_test.go文件,在go语言中,测试文件均已_test结尾&a…...
【多态】为什么析构函数的名称统一处理为destructor?
析构函数的名称统一处理为destructor的目的是为了解决析构函数的重写。 而这又引出了一个问题:为什么要进行析构函数的重写? 是为了下面这种情况: class Person { public:~Person() { cout << "~Person" << endl; } }…...
6.4 Case Studies - A Simple Logging Archive Class
下面这段内容介绍了一个示例,目的是帮助澄清"归档概念(Archive Concept)"的用法,以便用户可以实现自己的归档类。simple_log_archive.hpp 实现了一个简单但实用的归档类,用于将任何可序列化类型以可读的格式…...
【深度学习实验】前馈神经网络(九):整合训练、评估、预测过程(Runner)
目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. __init__(初始化) 2. train(训练) 3. evaluate(评估) 4. predict(预测) 5. save_model 6. load_model 7. 代码整合 一、实验介绍 二、实验环境 本系列实验使用…...
002-第一代硬件系统架构确立及产品选型
第一代硬件系统架构确立及产品选型 文章目录 第一代硬件系统架构确立及产品选型项目介绍摘要硬件架构硬件结构选型及设计单片机选型上位机选型扯点别的 关键字: Qt、 Qml、 信号采集机、 数据处理、 上位机 项目介绍 欢迎来到我们的 QML & C 项目ÿ…...
Go基础语法:指针和make和new
8 指针、make、new 8.1 指针(pointer) Go 语言中没有指针操作,只需要记住两个符号即可: & 取内存地址* 根据地址取值 package mainimport "fmt"func main() {a : 18// 获取 a 的地址值并复制给 pp : &a// …...
039_小驰私房菜_Camera perfermance debug
全网最具价值的Android Camera开发学习系列资料~ 作者:8年Android Camera开发,从Camera app一直做到Hal和驱动~ 欢迎订阅,相信能扩展你的知识面,提升个人能力~ 一、抓取trace 1. adb shell "echo vendor.debug.trace.perf=1 >> /system/build.prop" 2. …...
Caché for Windows安装及配置
本文介绍在Windows上安装Cach的操作步骤。本文假设用户熟悉Windows目录结构、实用程序和命令。本文包含如下主要部分: 1)Cach安装...
代码随想录算法训练营20期|第四十六天|动态规划part08|● 139.单词拆分 ● 关于多重背包,你该了解这些! ● 背包问题总结篇!
139.单词拆分 感觉这个板块要重新刷,完全没有印象 class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> set new HashSet<>(wordDict);boolean[] dp new boolean[s.length() 1];dp[0] true;for (int i…...
系统安装(一)CentOS 7 本地安装
CentOS与Ubuntu并称为Linux最著名的两个发行版,但由于笔者主要从事深度学习图像算法工作,Ubuntu作为谷歌和多数依赖库的亲儿子占据着最高生态位。但最近接手的一个项目里,甲方指定需要在CentOS7上运行项目代码,笔者被迫小小cos了一…...
obsidian使用指南
插入代码块快捷键设置 插入代码块 用英文搜索快捷键名字 英文搜索的【Insert code block】对应的是 (6个点) 中文搜索的【代码块】对应的是 (2个点) 查看word、excel等非md文件设置 电脑端obsidian->设置->文件与链接->检测所有类型文件->…...
【ardunio】青少年机器人四级实操代码(2023年9月)
目录 一、题目 二、示意图 三、流程图 四、硬件连接 1、舵机 2、超声波 3、LED灯 五、程序 一、题目 实操考题(共1题,共100分) 1. 主题: 迎宾机器人 器件:Atmega328P主控板1块,舵机1个,超声波传感器1个&…...
MYSQL的存储过程
存储过程 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。存储过程思想上很简单,就是…...
[kubernetes/docker] failed to resolve reference ...:latest: not found
问题描述: pod一直pending, kubectl describe pod ... 显示: Warning Failed 9s (x3 over 63s) kubelet Failed to pull image "mathemagics/my-kube-scheduler": rpc error: code NotFound desc failed to pull and unpack image "docker…...
彻底解决win11系统0x80070032
经过各种尝试,终于找到原因。第一个是电脑加密软件,第二个是需要的部分功能没有开启,第三个BIOS设置。个人觉得第三个不重要。 解决方法 笔记本型号 笔记本型号是Thinkpad T14 gen2。进入BIOS的按键是按住Enter键。 1、关闭山丽防水墙服务…...
解决因为修改SELINUX配置文件出错导致Faild to load SELinux poilcy无法进入CentOS7系统的问题
一、问题 最近学习Kubernetes,需要设置永久关闭SELINUX,结果修改错了一个SELINUX配置参数,关机重新启动后导致无法进入CentOS7系统,卡在启动进度条界面。 二、解决 多次重启后,在启动日志中发现 Faild to load SELinux poilcy…...
flask中的跨域处理-方法二不使用第三方库
方法1(第三方库) pip install flask-cors from flask import Flask from flask_cors import CORSapp = Flask(__name__) CORS(app, resources={r"/api/*": {"origins": ["http://localhost:63342", "http://localhost:63345"]}})方…...
矿山定位系统-矿井人员定位系统在矿山自动化安全监控过程中的应用
一,矿井人员定位系统现阶段使用的必要性 1,煤矿开采是一项非常特殊的工作,现场属于非常复杂多变的环境,井下信号极差,数据传输非常不稳定,人员安全难以保证,煤矿企业一直在研究如何使用更合适的…...
JS-ECharts-前端图表 多层级联合饼图、柱状堆叠图、柱/线组合图、趋势图、自定义中线、平均线、气泡备注点
本篇博客背景为JavaScript。在ECharts在线编码快速上手,绘制相关前端可视化图表。 ECharts官网:https://echarts.apache.org/zh/index.html 其他的一些推荐: AntV:https://antv.vision/zh chartcube:https://chartcub…...
【eslint】屏蔽语言提醒
在 JavaScript 中,ESLint 是一种常用的静态代码分析工具,它用于检测和提醒代码中的潜在问题和风格问题。有时候,在某些特定情况下,你可能希望临时屏蔽或禁用某些 ESLint 的提醒信息,以便消除不必要的警告或避免不符合项…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...
GAN模式奔溃的探讨论文综述(一)
简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...
