Golang 单元测试和基准测试实例详解

目录
  • 前言
  • Go 单元测试
  • 单元测试覆盖率
  • 基准测试

前言

多人协作的项目里,要保证代码的质量,自然离不开单元测试。开发完一个功能后肯定要对所写的代码进行测试,测试没有问题之后再合并到代码库供他人使用。如果强行合并到代码库可能会影响其他人开发,被上线的话肯定也会导致线上 Bug ,影响用户使用。

所以,单元测试也是一个很重要的事情。单元测试是指在开发中,对一个函数或模块的测试。其强调的是对单元进行测试。

Go 单元测试

Go 语言提供了单元测试的框架,只要遵循其规则即可:

测试文件命名:

  • 单元测试的代码文件都必须以 _test.go 结尾,这样才能被 Go 语言测试工具识别
  • 单元测试的文件命名都与被测试函数所在的 go 文件的文件名一样,然后再加 _test.go。比如 main.go 的测试文件 main_test.go

测试函数命名:

  • 单元测试的函数名必须以 Test 开头,再加上要测试函数名,且必须是公有的。比如main.go中有函数 func add(){},   其函数名应为 TestAdd
  • 测试函数的签名必须接收一个指向 testing.T 类型的指针,并且不能返回任何值
# main.go
func Add(){
    // to do something
}
# main_test.go
func TestAdd(t *testing.T) {
    result := Add()
    if result == 3 {
        println("success")
    } else {
        println("error")
    }
}

根据以上规则,就可以进行对某测试文件执行命令,进行单元测试:

go test -v ./main_test.go

如果显示的测试结果有 PASS 标记,说明单元测试通过。

单元测试覆盖率

函数是否被全面测试,还需要覆盖率进行检测。单元测试命令增加 --coverprofile 标记,就可以得到一个单元测试覆盖文件,且会在控制台打印出代码覆盖率是多少。

go test -v --coverprofile=main.cover ./main_test.go

Go 框架还可以生成 html 文件的覆盖率报告,这样就可以对单元测试覆盖率的结果更清晰,更明白。

go tool cover -html=main.cover -o=main.html

打开 html 文件就可以看到红色标记是没有被覆盖到,绿色是被测试到的。

以上是简单的功能的单元测试,验证功能逻辑的正确。但有时候还有性能的要求,这时就可以使用基准测试来评估代码的性能。

基准测试

基准测试是一项用于测试和评估软件性能指标的方法,主要测试代码的性能。基准测试的规则和单元测试的规则是不一样的:

  • 基准测试函数必须以 Benchmark 开头,且必须是可导出的
  • 函数的签名必须接收一个指向 testing.B 类型的指针,并且不能返回任何值;
  • 最后的 for 循环很重要,被测试的代码要放到循环里;
  • b.N 是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能。

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add()
    }
}

写完基准测试,就可以执行命令进行测试:

go test -bench=. ./

使用 go test 命令,再加上 -bench 这个 Flag,它接受一个表达式作为参数,以匹配基准测试的函数,"."表示运行所有基准测试。

BenchmarkAdd-10, 其中的 -10 是运行基准测试时对应的 GOMAXPROCS 的值。基准测试的时间默认是 1 秒,也就是 1 秒调用 1000000000 次、每次调用花费 311 纳秒。如果想让测试运行的时间更长,可以通过 -benchtime 指定,比如 3 秒。

go test -bench=. -benchtime=3s ./
  • 重置计时方法

进行基准测试之前,需要进行一些数据准备,如构建测试数据,而这部分准备工作不属于性能测试计算范围内所以需要排除在外。通过使用充值计数器 ResetTimer重新计算。也支持使用 StartTimer 和 StopTimer 方法,控制何时开始计时何时结束。

  • 内存统计

内存统计主要是统计每次操作分配内存的次数和分配的字节数。使用 ReportAllocs() 方法

func BenchmarkAdd(b *testing.B) {
    b.ResetTimer() // 重置计时时间
    b.ReportAllocs() // 内存统计
    for i := 0; i < b.N; i++ {
        Add()
    }
}

对以上命令执行后可在控制台上得到结果。多了两个指标。

  • 第一个表示:每次操作分配多少字节内存
  • 第二个表示:每次操作分配内存的次数

两个指标没有统一标准区说明越小越好还是越大越好,主要还是需要根据业务场景来判断的。

  • 并发基准测试

在并发的情况下,Go 也支持基准测试。Go 语言通过 RunParallel 方法运行并发基准测试。创建多个 goroutine 然后将 b.N 分配给这些 goroutine 执行。

func BenchmarkAdd(b *testing.B) {
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            Add()
        }
    })
}

单元测试可以保证代码质量,但其也不是万能的,还需要 code Review 和人工测试才能更好的保证代码的质量。

参考资料:https://www.jb51.net/article/260482.htm

以上就是Golang 单元测试和基准测试实例详解的详细内容,更多关于Golang 单元测试基准测试的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go语言单元测试模拟服务请求和接口返回

    目录 前言 httptest gock 安装 使用示例 总结 前言 这是Go单元测试从入门到放弃系列教程的第1篇,介绍了如何使用httptest和gock工具进行网络测试. 在上一篇<Go单元测试从入门到放弃—0.单元测试基础>中,我们介绍了Go语言编写单元测试的基础内容. 而实际工作中的业务场景往往会比较复杂,无论我们的代码是作为server端对外提供服务或者还是我们依赖别人提供的网络服务(调用别人提供的API接口)的场景,我们通常都不想在测试过程中真正的建立网络连接.本文就专门介绍如何在上

  • Go语言自带测试库testing使用教程

    目录 简介 单元测试 表格驱动测试 分组和并行 主测试函数 其他 性能测试 其他选项 示例测试 总结 简介 testing是 Go 语言标准库自带的测试库.在 Go 语言中编写测试很简单,只需要遵循 Go 测试的几个约定,与编写正常的 Go 代码没有什么区别.Go 语言中有 3 种类型的测试:单元测试,性能测试,示例测试.下面依次来介绍. 单元测试 单元测试又称为功能性测试,是为了测试函数.模块等代码的逻辑是否正确.接下来我们编写一个库,用于将表示罗马数字的字符串和整数互转.罗马数字是由M/D/

  • Go1.18新特性工作区模糊测试及泛型的使用详解

    目录 前言 Go工作区模式(Go Workspace Mode) 现实的情况 多仓库同时开发 多个新仓库开始开发 工作区模式是什么 推荐的使用方法 使用时的注意点 Go模糊测试(Go Fuzzing Test) 为什么Golang要支持模糊测试 模糊测试是什么 Golang的模糊测试如何使用 最简单的实践例子 提供自定义语料 使用时的注意点 Go的泛型 类型参数(Type Parameters) 类型集合(Type Sets) 类型推导(Type Inference) 类型统一化(Type Un

  • Go语言单元测试基础从入门到放弃

    目录 Go语言测试 go test工具 单元测试函数 格式 单元测试示例 go test -v go test -run 回归测试 跳过某些测试用例 子测试 表格驱动测试 介绍 示例 并行测试 使用工具生成测试代码 测试覆盖率 testify/assert 安装 使用示例 总结 Go语言测试 这是Go单测从入门到放弃系列教程的第0篇,主要讲解在Go语言中如何做单元测试以及介绍了表格驱动测试.回归测试,并且介绍了常用的断言工具. go test工具 Go语言中的测试依赖go test命令.编写测试

  • Go语言测试库testify使用学习

    目录 简介 准备工作 assert Contains DirExists ElementsMatch Empty EqualError EqualValues Error ErrorAs ErrorIs 逆断言 Assertions 对象 require mock suite 测试 HTTP 服务器 总结 简介 testify可以说是最流行的(从 GitHub star 数来看)Go 语言测试库了.testify提供了很多方便的函数帮助我们做assert和错误信息输出.使用标准库testing,

  • 详解Go 语言如何通过测试保证质量

    目录 引言 单元测试 什么是单元测试 Go 语言的单元测试 单元测试覆盖率 基准测试 什么是基准测试 Go 语言的基准测试 计时方法 内存统计 并发基准测试 基准测试实战 总结 引言 本节带你学习本专栏的第四模块:工程管理.现在项目的开发都不是一个人可以完成的,需要多人进行协作,那么在多人协作中如何保证代码的质量,你写的代码如何被其他人使用,如何优化代码的性能等, 就是第四模块的内容. 这一讲首先来学习 Go 语言的单元测试和基准测试. 单元测试 在开发完一个功能后,你可能会直接把代码合并到代码

  • Golang 单元测试和基准测试实例详解

    目录 前言 Go 单元测试 单元测试覆盖率 基准测试 前言 多人协作的项目里,要保证代码的质量,自然离不开单元测试.开发完一个功能后肯定要对所写的代码进行测试,测试没有问题之后再合并到代码库供他人使用.如果强行合并到代码库可能会影响其他人开发,被上线的话肯定也会导致线上 Bug ,影响用户使用. 所以,单元测试也是一个很重要的事情.单元测试是指在开发中,对一个函数或模块的测试.其强调的是对单元进行测试. Go 单元测试 Go 语言提供了单元测试的框架,只要遵循其规则即可: 测试文件命名: 单元测

  • Java Benchmark 基准测试的实例详解

    Java Benchmark 基准测试的实例详解 import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; import org.openjdk

  • unittest+coverage单元测试代码覆盖操作实例详解

    基于上一篇文章,这篇文章是关于使用coverage来实现代码覆盖的操作实例,源代码在上一篇已经给出相应链接. 本篇文章字用来实现代码覆盖的源代码,整个项目的测试框架如下: 就是在源代码的基础上加了一个CodeCover.py文件,执行该文件会在目录CoverageReport生成相应的覆盖报告.如下是CodeCover.py的源码: #coding=utf8 import os import time def findTestWithPath(): current_dir=os.getcwd()

  • springboot单元测试两种方法实例详解

    这篇文章主要介绍了springboot单元测试两种方法实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 springboot的单元测试,这里介绍两种方式,一种是在测试类中添加注解:另一种是在代码中启动项目的main方法中继承接口(也可以写在其他方法中). 如 对查看数据库的连接池信息 进行单元测试 1. 在类上使用注解: @RunWith(SpringRunner.class) @SpringBootTest @RunWith(Sprin

  • golang使用 gomodule 在公共测试环境管理go的依赖的实例详解

    背景:调试服务最好的方式就是直接上机实践.对在公司的员工来说,在同一套服务上协同开发比在单独的环境上开发,应该会更有感觉.有问题可以一起发现并解决,也能够一同开发需求. 但是,公司的测试机往往是没办法连外网的,而golang 的大部分工程都需要直接从github 上下载依赖,这就导致 依赖文件需要先提前上传到开发机上.那么当开发机上需要运行多个golang 工程的时候,如何共享这些依赖,减少维护依赖库的工作量呢? 这也是需要大家协作完成的- 最终总结:项目采用 go module + vendo

  • Golang基础教程之字符串string实例详解

    目录 1. string的定义 2.string不可变 3.使用string给另一个string赋值 4.string重新赋值 补充:字符串拼接 总结 1. string的定义 Golang中的string的定义在reflect包下的value.go中,定义如下: StringHeader 是字符串的运行时表示,其中包含了两个字段,分别是指向数据数组的指针和数组的长度. // StringHeader is the runtime representation of a string. // I

  • Golang实现Biginteger大数计算实例详解

    正文 Golang中的big.Int库支持大数计算,基于这个库封装了一层Bitinteger,支持字符串类型的大数,加减乘除等计算. 其他计算可以参考基于big.Int来实现. package BigIntege import ( "fmt" "math/big" ) const DecBase = 10 // BigInteger wrapper for big.Int type BigInteger struct { Value *big.Int } func

  • Golang基于JWT与Casbin身份验证授权实例详解

    目录 JWT Header Payload Signature JWT的优势 JWT的使用场景 Casbin Casbin可以做什么 Casbin不可以做什么 Casbin的工作原理 实践 登录接口请求 Token实现 使用Redis存储Token信息 用Casbin做授权管理 实现Casbin的策略 创建Todo JWT JSON Web Toekn(JWT)是一个开放标准RFC 7519,以JSON的方式进行通信,是目前最流行的一种身份验证方式之一. eyJhbGciOiJIUzI1NiIs

  • Golang 中反射的应用实例详解

    目录 引言 Golang类型设计原则 Golang 中为什么要使用反射/什么场景可以(应该)使用反射 举例场景: 反射的基本用法 反射的性能分析与优缺点 测试反射结构体初始化 测试结构体字段读取/赋值 测试结构体方法调用 优缺点 反射在 okr 中的简单应用 结论 引言 首先来一段简单的代码逻辑热身,下面的代码大家觉得应该会打印什么呢? type OKR struct { id int content string } func getOkrDetail(ctx context.Context,

  • spring对JDBC和orm的支持实例详解

    简介 Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术,如JDBC,Hibernate或者JDO等.它不仅可以让你方便地在这些持久化技术间切换, 而且让你在编码的时候不用考虑处理各种技术中特定的异常. 一致的异常层次 Spring提供了一种方便的方法,把特定于某种技术的异常,如SQLException, 转化为自己的异常,这种异常属于以 DataAccessException 为根的异常层次.这些异常封装了原始异常对象,这样就不会有丢失任何错误信息的

随机推荐