Go语言测试——【单元测试 | Mock测试 | 基准测试】

这篇具有很好参考价值的文章主要介绍了Go语言测试——【单元测试 | Mock测试 | 基准测试】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Go语言测试——【单元测试 | Mock测试 | 基准测试】

作者:非妃是公主
专栏:《Golang》
博客主页:https://blog.csdn.net/myf_666
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
Go语言测试——【单元测试 | Mock测试 | 基准测试】

软件测试:软件测试(英语:Software Testing),描述一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。换句话说,软件测试是一种实际输出与预期输出之间的审核或者比较过程。软件测试的经典定义是:在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。

软件测试的概念大家都很熟悉,他是为了发现程序中的错误,但永远也无法证明软件没有错误。

同时,软件测试按照测试策略可以分为单元测试集成测试回归测试等。按照测试用例的编写方法,又可以分成黑盒测试白盒测试等。

单元测试,是测试中成本最低,也最容易发现bug的一个缓解。对于不同的编程语言,一般有着不同的单元测试框架!就Go语言而言,有3个方面的测试——单元测试、Mock测试、基准测试。


一、单元测试

1. 测试文件命名

所有测试文件以_test结尾,如下图:
Go语言测试——【单元测试 | Mock测试 | 基准测试】


2. 测试函数

测试函数名字,为TestXxx,其中为函数名前加上Test,print.go示例如下:

package test

func HelloTom() string {
	return "非妃是公主"
}

print_test.go示例如下:

package test

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestHelloTom(t *testing.T) {
	output := HelloTom()
	expectOutput := "Tom"
	assert.Equal(t, expectOutput, output)
}

运行测试程序,测试输出如下:

Go语言测试——【单元测试 | Mock测试 | 基准测试】

修改函数返回为Tom后输出正常,如下:

Go语言测试——【单元测试 | Mock测试 | 基准测试】

值得注意的是,由于一些复杂的测试用例,需要在测试前进行初始化,这可以放在TestMain函数中进行定义,完成前置释放操作。

Go语言测试——【单元测试 | Mock测试 | 基准测试】


3. 测试覆盖率

如下运行后,可以在控制台看到测试覆盖率,具体操作如下:
Go语言测试——【单元测试 | Mock测试 | 基准测试】

从这里可以看到测试覆盖率情况,如下:

Go语言测试——【单元测试 | Mock测试 | 基准测试】


4. Tips

  • 一般测试覆盖率应该在50%~60%,较高覆盖率80%+。
  • 测试分支相互独立,全面覆盖。
  • 测试粒度足够小,函数单一职责。

二、Mock测试

Mock也叫做打桩,它的作用是可以降低程序不同模块之间的耦合度。比如,正常我们需要从一个文件中读取数据,然后再进行数据处理模块的测试,但是由于读取数据这部分也是存在代码的,也可能出现异常、错误。

如果最终测试没有通过,就存在两种可能:

  1. 文件读取存在问题;
  2. 数据处理存在问题。

为了使得出现错误的可能性更为单一,便于问题的定位。

我们就可以通过mock,将这部分的代码替换掉,生成虚拟数据,这时候,输入到数据处理函数中,这样就可以实现对数据处理模块的Mock测试。

下面为一个读取文件的函数:

func ReadFirstLine() string {
	open, err := os.Open("log")
	defer open.Close()
	if err != nil {
		return ""
	}
	scanner := bufio.NewScanner(open)
	for scanner.Scan() {
		return scanner.Text()
	}
	return ""
}

下面为数据处理函数:

func ProcessFirstLine() string {
	line := ReadFirstLine()
	destLine := strings.ReplaceAll(line, "11", "00")
	return destLine
}

我们要对处理函数进行测试,但是处理函数中是依赖一个ReadFirstLine这个函数的,常规的单元测试如下:

func TestProcessFirstLine(t *testing.T) {
	firstLine := ProcessFirstLine()
	assert.Equal(t, "line00", firstLine)
}

从上面可以看出,常规的单元测试就是正常调用ProcessFirstLine函数,因此需要调用ReadFirstLine里面的函数,会造成错误定位不精确的问题。

因此就需要将其返回值Mock,如下:

func TestProcessFirstLineWithMock(t *testing.T) {
	monkey.Patch(ReadFirstLine, func() string {
		return "line110"
	})
	defer monkey.Unpatch(ReadFirstLine)
	line := ProcessFirstLine()
	assert.Equal(t, "line000", line)
}

需要用到的库,如下:

import (
	"bou.ke/monkey"
	"github.com/stretchr/testify/assert"
	"testing"
)

这里的monkey是一个mock相关的库,通过它的patch函数,即可实现打桩,进而不再依赖本地文件。


三、基准测试

首先来看一下什么是基准测试,百度百科定义如下:

基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。例如,对计算机CPU进行浮点运算、数据访问的带宽和延迟等指标的基准测试,可以使用户清楚地了解每一款CPU的运算性能及作业吞吐能力是否满足应用程序的要求。1

下面来看一个负载均衡的例子,首先有10个服务器,每次选择一个服务器进行执行,代码如下:

import (
	"github.com/bytedance/gopkg/lang/fastrand"
	"math/rand"
)

var ServerIndex [10]int

func InitServerIndex() {
	for i := 0; i < 10; i++ {
		ServerIndex[i] = i+100
	}
}

func Select() int {
	return ServerIndex[rand.Intn(10)]
}

其中,initServerIndex是初始化服务器函数,Select即为随机选择一个服务器实现负载均衡。

基准测试函数命名以Benchmark开头,输入参数是testing.B,用b中的N值(即:b.N)反复递增循环测试。(如果Select的运行时间小于1s,那么N值将按照1、2、5、10、20、50……递增,直到递增到运行时间超过1s为止,然后去计算平均时间;如果超过1s,那么N就为1。)

这样处理的好处就是,可以使得求解得到的时间更加准确,不会收到机器运行状态的影响。

代码如下:

func BenchmarkSelect(b *testing.B) {
	InitServerIndex()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Select()
	}
}

其中,ResetTimer()为重置计时器,再Select操作前进行充值,可以使得时间检测更加准确。

以Parallel结尾标识多协程并发测试,测试代码如下:

func BenchmarkSelectParallel(b *testing.B) {
	InitServerIndex()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			Select()
		}
	})
}

1. 性能劣化

运行后发现,在并发情况下,代码性能存在一定的劣化。

Go语言测试——【单元测试 | Mock测试 | 基准测试】


2. 原因分析

分析原因,是由于rand为了保证全局的随机性和并发安全,持有了一把全局锁,进而影响了性能。


3. 性能优化

由于字节跳动公司后端主要采用Go语言,因此为了解决这一问题,字节跳动公司开源了一个高性能随机数方法 fastrand,开源地址为:https://github.com/bytedance/gopkg.

fastrand优化后的负载均衡代码如下:

import (
	"github.com/bytedance/gopkg/lang/fastrand"
)

func FastSelect() int {
	return ServerIndex[fastrand.Intn(10)]
}

Go语言测试——【单元测试 | Mock测试 | 基准测试】

从上图可以看出,无论是并发还是串行运行,FastSelect效率都比Select高。


4. 一个小疑问?

这里有一个疑问,知道的读者可以评论区回答一下。为什么串行的FastSelect运行时间是3.467ns,而并行的是0.5309ns呢?

这里我提出一种猜测,产生这种原因,可能和Timer的计时方法有关!比如利用如下公示:

E f f i c i e n c y = R u n T i m e N u m O p e r a t i o n s Efficiency=\frac{RunTime}{NumOperations} Efficiency=NumOperationsRunTime

其中,Efficiency用的就是ns/op作为单位,数值越小,表示消耗的时间越小,效率也就越高!RunTime单位为nsNumOperations指在这段时间内执行的操作数。

这样我们就可以解释问什么并行操作的效率更高了,因为我们在RunTime这段时间内有多个操作在并行执行,也就是分母会很大,这样效率也就会更高了。

总结一下,不难发现,基准测试主要是对程序的某一性能指标进行可对比的测试,然后点对点的进行性能的优化,因此更具有针对性


the end……

Go语言测试——单元测试、Mock测试、基准测试三部分的内容到这里就要结束啦~~

到此既是缘分,欢迎您的点赞评论收藏关注我,不迷路,我们下期再见!!

😘😘😘 我是Cherries,一位计算机科班在校大学生,写博客用来记录自己平时的所思所想!
💞💞💞 内容繁杂,又才疏学浅,难免存在错误,欢迎各位大佬的批评指正!
👋👋👋 我们相互交流,共同进步!

:本文由非妃是公主发布于https://blog.csdn.net/myf_666,转载请务必标明原文链接:https://blog.csdn.net/myf_666/article/details/128938363


  1. 百度百科——基准测试 ↩︎文章来源地址https://www.toymoban.com/news/detail-497101.html

到了这里,关于Go语言测试——【单元测试 | Mock测试 | 基准测试】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言基准测试(benchmark)三部曲之一:基础篇

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos Go的标准库内置的testing框架提供了基准测试(benchmark)功能,可以用来验证本地方法在串行或者并行执行时的基准表现,帮助开发者了解代码的真实性能情况,例如一个方法执行一次的平均耗时,还能

    2024年02月06日
    浏览(37)
  • Go语言基准测试(benchmark)三部曲之三:提高篇

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos -《Go语言基准测试(benchmark)三部曲》已近尾声,经历了《基础篇》和《内存篇》的实战演练,相信您已熟练掌握了基准测试的常规操作以及各种参数的用法,现在可以学习一些进阶版的技能了,在面

    2024年02月06日
    浏览(31)
  • Go语言单元测试

    Go语言中的测试依赖 go test 命令,go test 命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录 内,所有以 _test.go 为后缀名的源代码文件都是 go test 测试的一部分,不会被 go build 编译到最终的可执行 文件中。 在 *_test.go 文件中有三种类型的函数, 单元测试函数

    2024年02月11日
    浏览(34)
  • 【go语言开发】编写单元测试

    本文主要介绍使用go语言编写单元测试用例,首先介绍如何编写单元测试,然后介绍基本命令的使用,最后给出demo示例 在go语言中编写单元测试时,使用说明 测试文件命名 :在 Go 语言中,测试文件的命名应与被测试的源代码文件相同,但以 “_test” 结尾。例如,如果你的源

    2024年02月04日
    浏览(33)
  • 7 文件操作、单元测试、goroutine【Go语言教程】

    1.1 介绍 os.File 封装所有文件相关操作,File 是一个结构体 常用方法: 打开文件 关闭文件 1.2 应用实例 ①读文件 常用方法: ①bufio.NewReader(), reader.ReadString【带缓冲】 ②io/ioutil【一次性读取,适用于小文件】 读取文件的内容并显示在终端(带缓冲区的方式),使用 os.Open, file.

    2024年02月04日
    浏览(43)
  • 36-代码测试(上):如何编写Go语言单元测试和性能测试用例?

    每种语言通常都有自己的测试包/模块,Go语言也不例外。在Go中,我们可以通过 testing 包对代码进行单元测试和性能测试。  Go语言有自带的测试框架 testing ,可以用来实现单元测试(T类型)和性能测试(B类型),通过 go test 命令来执行单元测试和性能测试。 go test 执行测试

    2024年04月11日
    浏览(35)
  • Service层代码单元测试以及单元测试如何Mock

    接着上一篇文章:单元测试入门篇,本篇文章作为单元测试的进阶篇,主要介绍如何对Springboot Service层代码做单元测试,以及单元测试中涉及外调服务时,如何通过Mock完成测试。 现在项目都流行前后端代码分离,后端使用springboot框架,在service层编写接口代码实现逻辑。假设

    2023年04月08日
    浏览(37)
  • go benchmark 基准测试

    目录 一、benchmark的使用 1.一个简单的例子 2.运行用例 3.benchmark 是如何工作的 4.提升准确度 5.内存分配情况 6.测试不同的输入 二、benchmark的注意事项 1.ResetTimer 2.StopTimer StartTimer go mod init test 创建项目test,创建目录bench/fib 创建fib.go 创建fib_test.go go 不管是单元测试还是基准测试,

    2024年02月02日
    浏览(52)
  • java的单元测试-mock测试

    对于普通的方法,通常采用断言测试。 对于接口,需要使用mockMvc 对于未开发的功能,需要mockBean模拟一个业务bean java自身携带的工具类,也可以用于一些对抛出异常要求不高的业务或者存在全局异常的项目 另外有一个更加简单的写法,以assert开头 曾使用注入方式得到mockM

    2023年04月08日
    浏览(37)
  • Testify Mock 单元测试

    Testify 提供了单测方便的断言能力,这里的断言是将对代码实际返回的断言,代码的实际输出和预期是否一致。下面是 gin-gonic/gin 代码库的单测代码,Testify 还提供了很多其他的方法: 单元测试中也会存在不稳定的代码,我们的入参虽然保持不变,但每次单测的结果可能会发

    2024年02月03日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包