当前位置: 首页 > news >正文

golang单元测试性能测试常见用法

9c25ec5ae6cbdb2bb889ff4d4ef4ceda.jpeg

关于go test的一些说明

  • golang安装后可以使用go test工具进行单元测试 代码片段对比的性能测试,使用起来还是比较方便,下面是一些应用场景
    • 平时自己想做一些简单函数的单元测试,不用每次都新建一个main.go 然后go run main.go
    • 相对某个功能做下性能测试 看下cpu/内存消耗情况
  • 可以针对性的建立一些目录 存放自己的一些测试代码
  • 一些使用规则
    • 创建代码保存目录 这里以mytest目录为例
    • 目录下的文件名都要以_test.go结尾 比如common_test.go
    • package mytest 不要为main
    • import testing包
    • 普通单元测试 函数名以Test开头
    • 性能测试 函数名称以Benchmark开头
    • 目录下面函数名不要重名

普通单元测试常见用法

样例代码

  • common_test.go文件内容如下 一个加法函数一个乘法函数
  • package mytest
  • import "testing"

    // Add 加法
    func Add(a int, b int) int {
    return a + b
    }

    // Mul 乘法
    func Mul(a int, b int) int {
    return a * b
    }

    // 测试加法函数功能是否正常 正数
    func TestAddPositive(t *testing.T) {
    if ans := Add(1, 2); ans != 3 {
    t.Fatalf("1 + 2 expected be 3, but %d got", ans)
    }
    t.Log("TestAddPositive run Success")
    }

    // 测试加法函数功能是否正常 负数
    func TestAddNegative(t *testing.T) {
    if ans := Add(-10, -20); ans != -30 {
    t.Fatalf("-10 + -20 expected be -30, but %d got", ans)
    }
    t.Log("TestAddNegative run Success")
    }

    // 测试乘法函数功能是否正常
    func TestMul(t *testing.T) {
    if ans := Mul(3, 4); ans != 12 {
    t.Fatalf("3*4 expected be 12, but %d got", ans)
    }
    t.Log("TestMul run Success")
    }


指定文件测试

  • 命令 顺序测试文件中的所有函数
  • go test -v common_test.go
    • 假设mytest目录下有多个xx_test.go文件 想指定common_test.go文件中的所有函数
  • 输出
  • === RUN TestAddPositive
    common_test.go:20: TestAddPositive run Success
    --- PASS: TestAddPositive (0.00s)
    === RUN TestAddNegative
    common_test.go:28: TestAddNegative run Success
    --- PASS: TestAddNegative (0.00s)
    === RUN TestMul
    common_test.go:36: TestMul run Success
    --- PASS: TestMul (0.00s)
    PASS
    ok command-line-arguments 0.309s


指定测试某一个函数

  • 命令
  • go test -v -run TestAddPositive
    go test -run=TestAddPositive -v
    • 指定只测试目录下的TestAddPositive函数
  • 输出
  • === RUN TestAddPositive
    common_test.go:20: TestAddPositive run Success
    --- PASS: TestAddPositive (0.00s)
    PASS
    ok mytest 0.307s


指定测试某一类函数

  • 命令
  • go test -run=^TestAdd -v
    • 可以使用正则表达式 指定一类函数,比如想测试所有TestAdd开头的函数
  • 输出 会按照顺序测试目录下所有TestAdd打头的函数
  • === RUN TestAddPositive
    common_test.go:20: TestAddPositive run Success
    --- PASS: TestAddPositive (0.00s)
    === RUN TestAddNegative
    common_test.go:28: TestAddNegative run Success
    --- PASS: TestAddNegative (0.00s)
    PASS
    ok mytest 0.359s


测试目录下所有文件中的全部函数

  • 命令 会按照顺序测试目录下所有_test.go结尾的所有函数
  • go test -v .

性能测试的常见用法

样例代码

  • forRangeBenchMark_test.go样例代码如下
  • package mytest

    import "testing"

    // ************ benchmark range loop ************
    type Person struct {
    name [4096]byte
    age int
    }

    var (
    AllPerson [1024]Person
    )

    // BenchmarkForIndexVisit AllPerson[i].xxx 使用下标方式访问
    func BenchmarkForIndexVisit(b *testing.B) {
    for i := 0; i < b.N; i++ {
    var age int
    for i := 0; i < len(AllPerson); i++ {
    age = AllPerson[i].age
    }
    _ = age
    }
    }

    // BenchmarkRangeLoopVisit range循环的方式访问
    func BenchmarkRangeLoopVisit(b *testing.B) {
    for i := 0; i < b.N; i++ {
    var age int
    for _, person := range AllPerson {
    age = person.age
    }
    _ = age
    }
    }


-benchmem会打印内存申请信息,建议都打开这个选项

指定某一个文件测试

  • 命令
  • go test -bench=. -benchmem forRangeBenchMark_test.go
  • 输出
  • goos: darwin
    goarch: amd64
    cpu: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz
    BenchmarkForIndexVisit-6 4570186 246.8 ns/op 0 B/op 0 allocs/op
    BenchmarkRangeLoopVisit-6 4777 228750 ns/op 0 B/op 0 allocs/op
    PASS
    ok command-line-arguments 2.858s
  • 这里可以看出直接for range的方式遍历性能很差 因为for range会有一个临时变量复制的过程,这个过程比较消耗时间


指定某一个函数测试

  • 命令
  • go test -bench=BenchmarkRangeLoopVisit -benchmem
  • 输出
  • goos: darwin
    goarch: amd64
    pkg: mytest
    cpu: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz
    BenchmarkRangeLoopVisit-6 4657 345054 ns/op 0 B/op 0 allocs/op
    PASS
    ok mytest 1.950s


指定某一类函数

  • 命令
  • go test -bench=^BenchmarkRange -benchmem
    • 所有以BenchmarkRange打头的都会测试


指定测试时间

  • 命令
  • go test -bench=. -benchmem forRangeBenchMark_test.go -benchtime=5s
    • 默认1s 下面指定运行时间为5s
  • 输出
  • goos: darwin
    goarch: amd64
    cpu: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz
    BenchmarkForIndexVisit-6 24010926 248.3 ns/op 0 B/op 0 allocs/op
    BenchmarkRangeLoopVisit-6 24183 242653 ns/op 0 B/op 0 allocs/op
    PASS
    ok command-line-arguments 14.918s
    • BenchmarkForIndexVisit函数在5s内运行了24010926次 每次大概耗时 248.3 ns
    • BenchmarkRangeLoopVisit函数在5s内运行了24183次 每次大概耗时 242653 ns 性能相当差


指定测试次数

  • 命令
  • go test -bench=. -benchmem forRangeBenchMark_test.go -benchtime=10000x
  • 输出
  • goos: darwin
    goarch: amd64
    cpu: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz
    BenchmarkForIndexVisit-6 10000 246.6 ns/op 0 B/op 0 allocs/op
    BenchmarkRangeLoopVisit-6 10000 300624 ns/op 0 B/op 0 allocs/op
    PASS
    ok command-line-arguments 3.347s
    • 测试过程也可以看到BenchmarkRangeLoopVisit运行耗时很长,而BenchmarkForIndexVisit很快就结束了


性能测试-timer相关api

ResetTimer

  • 如果在 benchmark 开始前,需要一些准备工作,如果准备工作比较耗时,则需要将这部分代码的耗时忽略掉

StopTimer & StartTimer

  • 每次函数调用前后需要一些准备工作和清理工作,我们可以使用 StopTimer 暂停计时以及使用 StartTimer 开始计时
  • func Benchmarkxxx(b *testing.B) {
    for n := 0; n < b.N; n++ {
    b.StopTimer()
    // 准备数据
    b.StartTimer()
    Sort(nums)
    }
    }
    func Benchmarkxxx(b *testing.B) {
    //准备工作部分代码
    b.ResetTimer() // 重置定时器
    for n := 0; n < b.N; n++ {
    fib(30) // run fib(30) b.N times
    }
    }

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Linux 配置静态IP】Ubuntu20.04
  • MySQL双主双从实现方式
  • 音视频开发入门教程(2)配置FFmpeg编译 ~共210节
  • Scala学习笔记16: 注解
  • ‍我想我大抵是疯了,我喜欢上了写单元测试
  • 根据视图矩阵, 恢复相机的世界空间的位置
  • Elasticsearch 企业级实战 01:Painless 脚本如何调试?
  • OPPO 2024届校招正式批笔试题-后端(C卷)
  • LLM基础模型系列:Prompt-Tuning
  • 前端实现将多个页面导出为pdf(分页)
  • SSL vpn easy connect 选路连接失败,可能当前连接网络异常,请稍后重试
  • 防火墙--双机热备
  • python + Pytest + requests 的接口自动化步骤
  • SQL基础 | NOT NULL 约束介绍
  • 7.13实训日志
  • (三)从jvm层面了解线程的启动和停止
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • AHK 中 = 和 == 等比较运算符的用法
  • C++类的相互关联
  • Computed property XXX was assigned to but it has no setter
  • exports和module.exports
  • Facebook AccountKit 接入的坑点
  • HashMap剖析之内部结构
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • jquery ajax学习笔记
  • Laravel Mix运行时关于es2015报错解决方案
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • python docx文档转html页面
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • RxJS: 简单入门
  • Terraform入门 - 3. 变更基础设施
  • 闭包--闭包作用之保存(一)
  • 复习Javascript专题(四):js中的深浅拷贝
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 力扣(LeetCode)56
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 深入浅出Node.js
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​Java并发新构件之Exchanger
  • ​卜东波研究员:高观点下的少儿计算思维
  • # centos7下FFmpeg环境部署记录
  • #DBA杂记1
  • #知识分享#笔记#学习方法
  • (a /b)*c的值
  • (el-Date-Picker)操作(不使用 ts):Element-plus 中 DatePicker 组件的使用及输出想要日期格式需求的解决过程
  • (libusb) usb口自动刷新
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (十八)三元表达式和列表解析
  • (顺序)容器的好伴侣 --- 容器适配器
  • (四)opengl函数加载和错误处理
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略