专栏首页Go语言指北Go高阶18,go语言测试功能详解-上

Go高阶18,go语言测试功能详解-上

您诸位好啊,我是“菜鸟哥”--无尘,最早能看到这篇文章的小伙伴,也应该是中秋假期第一天了,首先祝大家中秋愉快,也感谢大家这么久以来的关注和支持。

在此佳节之际,作为回报,没有领到大闸蟹的, 可以在文章底部加我下微信,我来告诉你如何正确地吃一只大闸蟹?哈哈哈哈... 嗝~(留言有机会得红包)

对于 Go 语言的测试,我们之前写过一篇文章,简单介绍了下:单元测试,确保高质量代码的秘诀!,今天再来详细的介绍下。

目前 Go 测试系统支持单元测试、性能测试和示例测试:

  • 单元测试:单元测试是指对软件中的最小可测试单元进行检查和验证
  • 性能测试:性能测试,也称基准测试,是测量一个程序在固定工作负载下的性能。
  • 示例测试:广泛应用于 Go源码和各种开源框架中,用于展示某个包或某个方法的用法。

单元测试

单元测试就是对单元进行测试,一个单元可以是一个函数、一个模块等。

目录结构如下所示:

[ceshi]
  |--[gotest]
          |--unit.go
  |--[gotest_test]
          |--unit_test.go

unit.go 为源代码文件, unit_test.go 为测试文件。测试文件必须以“_test.go”结尾。

源代码文件 unit.go 代码:

package gotest

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

测试文件 unit_test.go 代码:

package gotest_test

import (
 "ceshi/gotest"
 "testing"
)

func TestAdd(t *testing.T){
 var a = 1
 var b = 2
 var expected = 3

 actual := gotest.Add(a, b)
 if actual != expected {
  t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected)
 }
}

测试文件可以跟源文件在同一个包,但多数情况是创建一个包专用于测试,这样可以使测试文件和源文件隔离。GO源代码以及其他知名的开源框架通常会创建测试包,而且规则是在原包名上加上”_test”。

执行测试

在测试文件所在目录中,使用 go test 命令即可启动单元测试,如下所示:

$ go test
PASS
ok      ceshi/gotest_test       0.818s

❝单元测试规则:

  1. 单元测试的 go 文件必须以 _test.go 结尾,Go 语言测试工具只认符合这个规则的文件。
  2. 单元测试文件名 _test.go 前面的部分最好是被测试的函数所在的 go 文件的文件名。
  3. 单元测试的函数名必须以 Test 开头,是可导出的、公开的函数。
  4. 测试函数的签名必须接收一个指向 testing.T 类型的指针,且不能返回任何值。
  5. 函数名最好是 Test + 被测试的函数名。

性能测试(基准测试)

基准测试函数和普通测试函数写法类似,但是以Benchmark为前缀名,并且带有一个*testing.B类型的参数;*testing.B参数除了提供和*testing.T类似的方法,还有额外一些和性能测量相关的方法。它还提供了一个整数 N,用于指定操作执行的循环次数。

目录结构如下所示:

[ceshi]
  |--[gotest]
          |--benchmark.go
  |--[gotest_test]
          |--benchmark_test.go

benchmark.go 为源代码文件, benchmark_test.go 为测试文件。

源代码文件 benchmark.go 代码:

package gotest

//不预分配
func Slice1() []int {
 var newSlice []int

 for i := 0; i < 100000; i++ {
  newSlice = append(newSlice, i)
 }

 return newSlice
}

//预分配Slice的存储空间构造
func Slice2() []int {
 var newSlice []int

 newSlice = make([]int, 0, 100000)
 for i := 0; i < 100000; i++ {
  newSlice = append(newSlice, i)
 }

 return newSlice
}

两个方法都构造一个容量 100000 的切片,所不同的是 Slice1() 不预先分配内存, Slice2() 会预先分配内存,本次来测试一下二者的性能差异。

测试文件 benchmark_test.go 代码:

package gotest_test

import (
 "ceshi/gotest"
 "testing"
)

func BenchmarkSlice1(b *testing.B) {
 for i := 0; i < b.N; i++ {
  gotest.Slice1()
 }
}

func BenchmarkSlice2(b *testing.B) {
 for i := 0; i < b.N; i++ {
  gotest.Slice2()
 }
}

执行测试

$ go test -bench=.
goos: windows
goarch: amd64
pkg: ceshi/gotest_test
cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
BenchmarkSlice1-12          2539            474179 ns/op
BenchmarkSlice2-12         10000            109779 ns/op
PASS
ok      ceshi/gotest_test       4.018s

其中 -bench 为 go test 的 flag,该 flag 指示 go test 进行性能测试。 通过输出可以直观的看出, BenchmarkSlice1 执行了2539次,平均每次 474179 纳秒, BenchmarkSlice2 执行了10000次,平均每次 109779 纳秒。 从测试结果上看,虽然构造切片很快,但通过给切片预分配内存,性能还可以进一步提升,符合预期。

❝性能测试规则:

  1. 文件名必须以“_test.go”结尾;
  2. 函数名必须以“Benchmark”开始;
  3. 使用命令“go test -bench=.”开始性能测试;

示例测试

目录结构如下所示:

[ceshi]
  |--[gotest]
          |--example.go
  |--[gotest_test]
          |---example_test.go

example.go 为源代码文件, example_test.go 为测试文件。

源代码文件 example.go 代码:

package gotest

import "fmt"

//一行打印输出
func SayHello() {
 fmt.Println("Hello 微客鸟窝")
}

//两行打印输出
func SayGoodbye() {
 fmt.Println("微客鸟窝,")
 fmt.Println("goodbye")
}

//多行打印输出,由于Map数据结构的原因,多行打印次序是随机的。
func PrintName() {
 name := make(map[int]string, 4)
 name[1] = "微"
 name[2] = "客"
 name[3] = "鸟"
 name[4] = "窝"

 for _, value := range name {
  fmt.Println(value)
 }
}

测试文件 example_test.go 代码:

package gotest_test

import "ceshi/gotest"

func ExampleSayHello() {
 gotest.SayHello()
 // OutPut: Hello 微客鸟窝
}

func ExampleSayGoodbye() {
 gotest.SayGoodbye()
 // OutPut:
 // 微客鸟窝,
 // goodbye
}

func ExamplePrintName() {
 gotest.PrintName()
 //Unordered output:
 //微
 //客
 //鸟
 //窝
}

例子测试函数命名规则为”Examplexxx”,其中”xxx”为自定义的标识,通常为待测函数名称。

执行测试

$ go test example_test.go
ok      command-line-arguments  0.605s

❝示例测试规则:

  1. 例子测试函数名需要以”Example”开头;
  2. 检测单行输出格式为“// Output: <期望字符串>”;
  3. 检测多行输出格式为“// Output: \ <期望字符串> \ <期望字符串>”,每个期望字符串占一行;
  4. 检测无序输出格式为”// Unordered output: \ <期望字符串> \ <期望字符串>”,每个期望字符串占一行;
  5. 测试字符串时会自动忽略字符串前后的空白字符;
  6. 如果测试函数中没有“Output”标识,则该测试函数不会被执行;
  7. 执行测试可以使用 go test ,此时该目录下的其他测试文件也会一并执行;
  8. 执行测试可以使用 go test <xxx_test.go> ,此时仅执行特定文件中的测试函数;


图片及部分相关技术知识点来源于网络搜索,侵权删!

参考资料:

https://kaiwu.lagou.com/course/courseInfo.htm?sid=&courseId=536&lagoufrom=noapp#/sale

《Go专家编程》

http://shouce.jb51.net/gopl-zh/ch10/ch10-07.html

本文分享自微信公众号 - 微客鸟窝(gophpython),作者:有码无尘

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-09-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Go高阶指南19,测试功能详解-下

    子测试可以使多个测试函数共用部分代码,比如有两个测试函数 A 和 B,有相同的初始化程序,使用子测试函数可以将A、B函数合并到一个函数中,对于它们相同的初始化程...

    微客鸟窝
  • Go 语言学习路线来啦

    时不时的有人问我一些关于 Go 语言学习路线、学习资源方面的问题,这篇文章就来详细说一说。借此希望给那些正在学习,或是想学习 Go 语言的朋友一些帮助。

    roseduan
  • Go开发者路线图2019,请收下这份指南

    Go是Google开发的一种静态、强类型、编译型、并发型,并具有垃圾回收功能的类C编程语言。2009以开源项目的形式发布,2012年发布1.0稳定版本,距今已经...

    AI科技大本营
  • go 单元测试基本篇

    go 语言本身内置了一套相对轻量级的测试框架,通过 testing 库和 go test 命令支持单元测试。本篇文档主要介绍使用 go 语言 testing 包...

    腾讯云数据库团队
  • Go语言基础、进阶、提高课程--第一节:环境安装

    干货来了!!!为了让更多的小伙伴喜欢Golang、加入Golang之中来,Golang语言社区发起人彬哥联合业界大牛共同推出了Go语言基础、进阶、提高课程,目前...

    李海彬
  • GitHub上优秀的Go开源项目

    近一年来,学习和研究Go语言,断断续续的收集了一些比较优秀的开源项目,这些项目都非常不错,可以供我们学习和研究Go用,从中可以学到很多关于Go的使用、技巧以及相...

    我的小碗汤
  • [GO语言基础] 一.为什么我要学习Golang以及GO语言入门普及

    作为网络安全初学者,会遇到采用Go语言开发的恶意样本。因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识;另一方面是分享与读者,希...

    Eastmount
  • 开源巨献:Google最热门60款开源项目

    作者:程序猿(微信号:imkuqin) 猿妹 链接:https://www.itcodemonkey.com/article/329.html(点击尾部阅读原...

    顶级程序员
  • 开源巨献:Google最热门60款开源项目

    0、机器学习系统 TensorFlow ★Star 62533 ? TensorFlow 是谷歌的第二代机器学习系统,按照谷歌所说,在某些基准测试中,Tenso...

    前朝楚水
  • Go 单元测试和性能测试

    测试对于互联网应用软件开发来说非常重要,它对软件可靠性保证具有重要意义,通过测试能够尽可能发现并改正软件中的错误,提高软件质量。

    孤烟
  • 第七节 Go语言运算符

    干货来了!!!为了让更多的小伙伴喜欢Golang、加入Golang之中来,Golang语言社区发起人彬哥联合业界大牛共同推出了Go语言基础、进阶、提高课程,目前...

    李海彬
  • 适合 Go 新手学习的开源项目——在 GitHub 学编程

    故事要从 2007 年说起。因为受够了 C++ 煎熬的 Google 首席软件工程师 Rob Pike 召集 Robert Griesemer 和 Ken Th...

    HelloGitHub
  • 听说go语言越来越火了?那么请收下这一份go语言书单吧!

    Go 是一种简单、小巧、令人愉悦的语言。它也有一些犄角旮旯,但绝大部分是经过精心设计的。它的学习速度令人难以置信,并且规避了其他语言中一些不那么广为人知的特性。

    黄小斜学Java
  • 听说go语言越来越火了?那么请收下这一份go语言书单吧!

    Go 是一种简单、小巧、令人愉悦的语言。它也有一些犄角旮旯,但绝大部分是经过精心设计的。它的学习速度令人难以置信,并且规避了其他语言中一些不那么广为人知的特性。

    黄小斜学Java
  • dubbo-go 的开发、设计与功能介绍

    dubbo-go 是目前 Dubbo 多语言生态最火热的项目。dubbo-go 最早的版本应该要追溯到 2016 年,由社区于雨同学编写 dubbo-go 的初...

    Java帮帮
  • dubbo-go介绍

    dubbo-go 是目前 Dubbo 多语言生态最火热的项目。dubbo-go 最早的版本应该要追溯到 2016 年,由社区于雨同学编写 dubbo-go 的初...

    heidsoft
  • 将python用go写

    对于一个老鸟程序员来说,仅仅掌握一门语言是不够的。现在python感觉用烂了,连公司的HR,销售的美女们都在学。

    赵云龙龙
  • 深度解密Go语言之unsafe

    个人认为,学习本身并不是一件轻松愉快的事情,寓教于乐是个美好的愿望。想要深刻地领悟,就得付出别人看不见的努力。学习从来都不会是一件轻松的事情,枯燥是正常的。耐住...

    梦醒人间
  • 你知道Golang源码各目录的作用吗?

    主要用于文本的读取写入,对io.Reader和io.Writer进行了实现和封装,提供了比较便利的方法操作文件。

    平也

扫码关注云+社区

领取腾讯云代金券