阅读目录

  • 测试工具 :go test
    • 1 运行整个项目的测试文件
    • 2 只运行某个测试文件
    • 3 加 -v 查看详细的结果
    • 4 只测试某个函数
    • 5 生成 test 的二进制文件:加 -c 参数
    • 6 执行这个 test 测试文件:加 -o 参数
    • 7 测试安装/重新安装 依赖包,而不运行代码:加 -i 参数
  • 单元测试
  • 表组测试
  • 理清 Go 中晦涩难懂的寻址问题
    • 哪些是可以寻址的?
      • 变量:&x
      • 指针:&*x
      • 数组元素索引: &a[0]
      • 切片
      • 切片元素索引:&s[1]
      • 组合字面量不可寻址字段属性可寻址
    • 哪些是不可以寻址的?
      • 常量
      • 字符串
      • 函数或方法
      • 基本类型字面量
      • map 中的元素
      • 数组字面量进行切片操作

测试工具 :go test

go test 本身可以携带很多的参数,熟悉这些参数,可以让我们的测试过程更加方便。

1 运行整个项目的测试文件

$ go test
PASS
ok      _/home/wangbm/golang/math   0.003s

2 只运行某个测试文件

math_test.go
math.go 是一对,缺一不可,前后顺序可对调。

$ go test math_test.go math.go
ok      command-line-arguments  0.002s

3 加 -v 查看详细的结果

$ go test math_test.go math.go
=== RUN   TestAddTestAdd: main_test.go:22: the result is okTestAdd: main_test.go:22: the result is okTestAdd: main_test.go:22: the result is okTestAdd: main_test.go:22: the result is okTestAdd: main_test.go:22: the result is ok
--- PASS: TestAdd (0.00s)
PASS
ok      command-line-arguments  0.003s

4 只测试某个函数

-run 支持正则,如下例子中 TestAdd,如果还有一个测试函数为 TestAdd02,那么它也会被运行。

$ go test -v -run="TestAdd"
=== RUN   TestAddTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is ok
--- PASS: TestAdd (0.00s)
PASS
ok      _/home/wangbm/golang/math   0.003s

5 生成 test 的二进制文件:加 -c 参数

$ go test -v -run="TestAdd" -c
$
$ ls -l
total 3208
-rw-r--r-- 1 root root      95 May 25 20:56 math.go
-rwxr-xr-x 1 root root 3272760 May 25 21:00 math.test
-rw-r--r-- 1 root root     525 May 25 20:56 math_test.go

6 执行这个 test 测试文件:加 -o 参数

$ go test -v -o math.test
=== RUN   TestAddTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is okTestAdd: math_test.go:22: the result is ok
--- PASS: TestAdd (0.00s)
=== RUN   TestAumTestAum: math_test.go:30: 6
--- PASS: TestAum (0.00s)
PASS
ok      _/home/wangbm/golang/math   0.002s

7 测试安装/重新安装 依赖包,而不运行代码:加 -i 参数

# 这里没有输出
$ go test -i

单元测试

准备两个 Go 文件::

E:\TEXT\test_go\test\math\math.go

package mathfunc Add(x, y int) int {return x + y
}

E:\TEXT\test_go\test\math\math_test.go

package mathimport "testing"func TestAdd(t *testing.T) {t.Log(Add(1, 2))
}

然后使用 go test 工具去执行:

PS E:\TEXT\test_go\test\math> go test .
ok      test/math       0.365s
PS E:\TEXT\test_go\test\math>PS E:\TEXT\test_go\test\math> go test . -v
=== RUN   TestAddmath_test.go:6: 3
--- PASS: TestAdd (0.00s)
PASS
ok      test/math       0.359s
PS E:\TEXT\test_go\test\math>

从上面这个例子中,可以总结中几点 Go 语言测试框架要遵循的规则:

  1. 单元测试代码的 go文件必须以 _test.go 结尾,而前面最好是被测试的文件名(不过并不是强制的),比如要测试 math.go 测试文件名就为 math_test.go。
  2. 单元测试的函数名必须以Test开头,后面直接跟要测试的函数名,比如要测试 Add函数,单元测试的函数名就得是 TestAdd。
  3. 单元测试的函数必须接收一个指向 testing.T 类型的指针,并且不能返回任何值。

表组测试

Add(1, 2) 是一次单元测试的场景,而 Add(2, 4) ,Add(3, 6) 又是另外两种单元测试的场景。

对于多种输入场景的测试,我们可以同时放在 TestAdd 里进行测试,这种测试方法就是表组测试。

修改 E:\TEXT\test_go\test\math\math_test.go 如下:

package mathimport "testing"func TestAdd(t *testing.T) {sum := Add(1, 2)if sum == 3 {t.Log("the result is ok")} else {t.Fatal("the result is wrong")}sum = Add(2, 4)if sum == 6 {t.Log("the result is ok")} else {t.Fatal("the result is wrong")}
}
PS E:\TEXT\test_go\test\math> go test . -v
=== RUN   TestAddmath_test.go:8: the result is okmath_test.go:15: the result is ok
--- PASS: TestAdd (0.00s)
PASS
ok      test/math       0.356s
PS E:\TEXT\test_go\test\math>

如果输入的场景实在太多(比如下面用的五组输入),用上面的方法,可能需要写很多重复的代码,这时候可以利用表格测试法

E:\TEXT\test_go\test\math\math_test.go

package mathimport ("fmt""testing"
)type TestTable struct {xarg intyarg int
}func TestAdd(t *testing.T) {tables := []TestTable{{1, 2},{2, 4},{4, 8},{5, 10},{6, 12},}for _, table := range tables {result := Add(table.xarg, table.yarg)if result == (table.xarg + table.yarg) {t.Log("" + fmt.Sprintf("the result is ok %d", result))} else {t.Fatal("the result is wrong")}}
}
PS E:\TEXT\test_go\test\math> go test . -v
=== RUN   TestAddmath_test.go:25: the result is ok 3math_test.go:25: the result is ok 6math_test.go:25: the result is ok 12math_test.go:25: the result is ok 15math_test.go:25: the result is ok 18
--- PASS: TestAdd (0.00s)
PASS
ok      test/math       0.351s
PS E:\TEXT\test_go\test\math>

理清 Go 中晦涩难懂的寻址问题

什么叫可寻址?

可直接使用 & 操作符取地址的对象,就是可寻址的(Addressable)。

E:\TEXT\test_go\test\math\math.go

package mathimport "fmt"func Unit() {name := "heihie"fmt.Println(&name)
}

E:\TEXT\test_go\test\math\math_test.go

PS E:\TEXT\test_go\test\math> go test . -v
=== RUN   TestUnit
0xc0000505a0
--- PASS: TestUnit (0.00s)
PASS
ok      test/math       0.313s
PS E:\TEXT\test_go\test\math>

程序运行不会报错,说明 name 这个变量是可寻址的。

但不能说 “iswbm” 这个字符串是可寻址的。

“iswbm” 是字符串,字符串都是不可变的,是不可寻址的,后面会介绍到。

在开始逐个介绍之前,先说一下结论:

  • 指针可以寻址:&Profile{}

  • 变量可以寻址:name := Profile{}

  • 字面量通通不能寻址:Profile{}

哪些是可以寻址的?

变量:&x

func main() {name := "iswbm"fmt.Println(&name)// output: 0xc000010200
}

指针:&*x

type Profile struct {Name string
}func main() {fmt.Println(unsafe.Pointer(&Profile{Name: "iswbm"}))// output: 0xc000108040
}

数组元素索引: &a[0]

func main() {s := [...]int{1,2,3}fmt.Println(&s[0])// output: xc0000b4010
}

切片

func main() {fmt.Println([]int{1, 2, 3}[1:])
}

切片元素索引:&s[1]

func main() {s := make([]int , 2, 2)fmt.Println(&s[0])// output: xc0000b4010
}

组合字面量不可寻址字段属性可寻址

所有的组合字面量都是不可寻址的,就像下面这样子

type Profile struct {Name string
}func new() Profile {return Profile{Name: "iswbm"}
}func main() {fmt.Println(&new())// cannot take the address of new()
}

注意上面写法与这个写法的区别,下面这个写法代表不同意思,其中的 & 并不是取地址的操作,而代表实例化一个结构体的指针。

type Profile struct {Name string
}func main() {fmt.Println(&Profile{Name: "iswbm"}) // ok
}

虽然组合字面量是不可寻址的,但却可以对组合字面量的字段属性进行寻址(直接访问)

type Profile struct {Name string
}func new() Profile {return Profile{Name: "iswbm"}
}func main() {fmt.Println(new().Name)
}

哪些是不可以寻址的?

常量

import "fmt"const VERSION  = "1.0"func main() {fmt.Println(&VERSION)
}

字符串

func getStr() string {return "iswbm"
}
func main() {fmt.Println(&getStr())// cannot take the address of getStr()
}

函数或方法

func getStr() string {return "iswbm"
}
func main() {fmt.Println(&getStr)// cannot take the address of getStr
}

基本类型字面量

字面量分:基本类型字面量复合型字面量

基本类型字面量,是一个值的文本表示,都是不应该也是不可以被寻址的。

func getInt() int {return 1024
}func main() {fmt.Println(&getInt())// cannot take the address of getInt()
}

map 中的元素

字典比较特殊,可以从两个角度来反向推导,假设字典的元素是可寻址的,会出现 什么问题?

  1. 如果字典的元素不存在,则返回零值,而零值是不可变对象,如果能寻址问题就大了。
  2. 而如果字典的元素存在,考虑到 Go 中 map 实现中元素的地址是变化的,这意味着寻址的结果也是无意义的。

基于这两点,Map 中的元素不可寻址,符合常理。

func main() {p := map[string]string {"name": "iswbm",}fmt.Println(&p["name"])// cannot take the address of p["name"]
}

搞懂了这点,你应该能够理解下面这段代码为什么会报错啦~

E:\TEXT\test_go\test\math\math.go

package mathimport "fmt"type Person struct {Name  stringEmail string
}func Unit() {m := map[int]Person{1: Person{"Andy", "1137291867@qq.com"},2: Person{"Tiny", "qishuai231@gmail.com"},3: Person{"Jack", "qs_edu2009@163.com"},}//编译错误:cannot assign to struct field m[1].Name in map// m[1].Name = "Scrapup"fmt.Println(m[1].Name)
}

E:\TEXT\test_go\test\math\math_test.go

package mathimport ("fmt""testing"
)func TestUnit(t *testing.T) {Unit()
}func TestCc(t *testing.T) {fmt.Println("hello")
}
PS E:\TEXT\test_go\test\math> go test -v -run="TestUnit"
=== RUN   TestUnit
Andy
--- PASS: TestUnit (0.00s)
PASS
ok      test/math       0.339s
PS E:\TEXT\test_go\test\math>

解决map修改值的方法

package mathimport "fmt"type Person struct {Name  stringEmail string
}func Unit() {m := map[int]Person{1: Person{"Andy", "1137291867@qq.com"},2: Person{"Tiny", "qishuai231@gmail.com"},3: Person{"Jack", "qs_edu2009@163.com"},}// 创建一个新的PersonnewPerson := Person{Name: "Scrapup", Email: "1137291867@qq.com"}// 创建一个新的mapnewMap := make(map[int]Person)// 遍历原始mapfor k, v := range m {// 如果键值不等于1,则复制元素if k != 1 {newMap[k] = v} else {// 否则,添加新的PersonnewMap[k] = newPerson}}// 将新的map赋值给原始mapm = newMap//打印结果for k, v := range m {fmt.Printf("key is %d, value is %v)\n", k, v)}
}

数组字面量进行切片操作

数组字面量是不可寻址的,当你对数组字面量进行切片操作,其实就是寻找内部元素的地址,下面这段代码是会报错的。

func main() {fmt.Println([3]int{1, 2, 3}[1:])// invalid operation [3]int literal[1:] (slice of unaddressable value)
}

Golang 测试工具 go test相关推荐

  1. php 压测流量回放,终极 Web 应用性能和压力测试工具 Gor

    常见的 Web 应用的压力测试工具 Web 应用压力测试工具有很多,比如 Apache ab,node-ab,Apache JMeter, LoadRunner, httperf.但是这些工具都没能解 ...

  2. 使用 WRK 压力测试工具对 ASP.NET Core 的接口进行压力测试

    0. 简要介绍 WRK 是一款轻量且易用的 HTTP 压力测试工具,通过该工具我们可以方便地对我们所开发的 WebAPI 项目进行压力测试,并且针对测试的情况返回结果. PS:Wrk 并不能针对测试的 ...

  3. 推荐几个 Go 测试工具和技巧让你在虎年如虎添翼

    今天带来一篇让你在虎年如虎添翼的Go测试工具和技巧的文章分享.大体内容翻译于 Go (Golang): Testing tools & tips to step up your game[1] ...

  4. 简单易用线上引流测试工具:GoReplay

    一. 引流测试产生背景 日常大部分的测试工作都是在测试环境下,通过模拟用户的行为来对系统进行验证,包括功能以及性能.在这个过程中,你可能会遇到以下问题: 用户访问行为比较复杂,模拟很难和用户行为一致, ...

  5. Golang可视化工具——go-callvis

    Golang可视化工具--go-callvis 一.go-callvis介绍 二.运行依赖 三.安装 四.使用方法 五.效果图说明 参考 一.go-callvis介绍 Go-callvis是一种gol ...

  6. Go入门系列(十八) 反射、包和测试工具

    本系列文章目录 展开/收起 Go入门系列(一) 初识Go语言 Go入门系列(二) 变量.指针.数据类型简介和作用域 Go入门系列(三) 基础类型--整型.浮点型.布尔类型和字符串 Go入门系列(四) ...

  7. linux 渗透工具_适用于Linux的十大最佳渗透测试工具

    linux 渗透工具 This article covers some of the best penetration testing tools for Linux Cybersecurity is ...

  8. 来自GitHub的系列渗透测试工具

    渗透测试 Kali - GNU / Linux发行版,专为数字取证和渗透测试而设计.(Kali Linux | Penetration Testing and Ethical Hacking Linu ...

  9. 高性能 HTTP 负载测试工具 Vegeta

    什么是 Vegeta Vegeta 是一个用 Go 语言编写的多功能的 HTTP 负载测试工具,它提供了命令行工具和一个开发库. 官方地址:https://github.com/tsenart/veg ...

最新文章

  1. layer output 激活函数_一文彻底搞懂BP算法:原理推导+数据演示+项目实战(下篇)...
  2. dubbo源码分析(3)
  3. NOIP模拟测试7「方程的解·visit」
  4. Linux C 中字符串化操作符#
  5. python 直方图排序_利用直方图对lis进行排序
  6. 华为机试HJ1:字符串最后一个单词的长度
  7. 2018-01-03 烂尾工程: Java实现的汇编语言编译器
  8. 2021-11-23日win10更新bug:共享打印机无法连接的修复
  9. 3dmax渲染出来的图不清晰?
  10. java bs和cs_BS与CS的区别和联系
  11. 关于如何保持图片分辨率并压缩图片存储大小
  12. pulseaudio如何开通系统日志来debug
  13. 008高级用法markdown编写幻灯片
  14. Java.lang.Class类 isArray()方法有什么功能呢?
  15. onload的具体使用
  16. 一名优秀的数据分析师,应该具备哪些基本素质?
  17. Android学习之Android历史
  18. MAC修改主机名、计算机名
  19. flutter CustomPainter 简单绘制 三角形 多边形
  20. 能力不够,你就态度好点

热门文章

  1. 公司题库-运维方向-2018-04-26-待续
  2. 人老了,到底是应该多运动还是多静养?跳广场舞要注意啥?
  3. centos7 安装psutil
  4. 并发、并行傻傻分不清楚?线程的一生都经历些什么?
  5. L1-033 出生年 (15 分)(简单解法)
  6. 2018年最佳设计规范20例免费下载
  7. 专访 Zipkin 项目 Leader:如何用 Zipkin 做好分布式追踪?
  8. 压缩包的密码如何删除?
  9. 博弈论Python仿真(一)
  10. Redis 设计与实现重点回顾