Golang 测试工具 go test

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

测试工具 :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   TestAdd
    TestAdd: main_test.go:22: the result is ok
    TestAdd: main_test.go:22: the result is ok
    TestAdd: main_test.go:22: the result is ok
    TestAdd: main_test.go:22: the result is ok
    TestAdd: 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   TestAdd
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: 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   TestAdd
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
    TestAdd: math_test.go:22: the result is ok
--- PASS: TestAdd (0.00s)
=== RUN   TestAum
    TestAum: 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 math

func Add(x, y int) int {
	return x + y
}

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

package math

import "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   TestAdd
    math_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 math

import "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   TestAdd
    math_test.go:8: the result is ok
    math_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 math

import (
	"fmt"
	"testing"
)

type TestTable struct {
	xarg int
	yarg 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   TestAdd
    math_test.go:25: the result is ok 3
    math_test.go:25: the result is ok 6
    math_test.go:25: the result is ok 12
    math_test.go:25: the result is ok 15
    math_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 math

import "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 math

import "fmt"

type Person struct {
	Name  string
	Email 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 math

import (
	"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 math

import "fmt"

type Person struct {
	Name  string
	Email 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"},
	}

	// 创建一个新的Person
	newPerson := Person{Name: "Scrapup", Email: "1137291867@qq.com"}
	// 创建一个新的map
	newMap := make(map[int]Person)

	// 遍历原始map
	for k, v := range m {
		// 如果键值不等于1,则复制元素
		if k != 1 {
			newMap[k] = v
		} else {
			// 否则,添加新的Person
			newMap[k] = newPerson
		}
	}
	// 将新的map赋值给原始map
	m = newMap
	//打印结果
	for k, v := range m {
		fmt.Printf("key is %d, value is %v)\n", k, v)
	}
}

数组字面量进行切片操作

数组字面量是不可寻址的,当你对数组字面量进行切片操作,其实就是寻找内部元素的地址,下面这段代码是会报错的。文章来源地址https://www.toymoban.com/news/detail-726042.html

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

到了这里,关于Golang 测试工具 go test的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • API Testing 一个基于 YAML 文件的开源接口测试工具

    目录 前言: 如何使用? 本地模式 服务端模式 文件格式 后续计划 API Testing 是一个基于 YAML 文件的开源接口测试工具,它可以帮助开发者快速地进行接口测试。 在选择工具时,可以从很多方面进行考量、对比,以下几点是该工具的特色或者优点:

    2024年02月16日
    浏览(33)
  • 【Cmake】Ctest测试工具 cmake命令之add_test和set_tests_properties使用案例

    目录 前言 一、初识CTest 二、使用方法 三、完整的简单测试工程 附录 附录一 cmake命令 enable_testing add_test 原文:CTest - https://www.cnblogs.com/457220157-FTD/p/4139149.html        CTest是CMake集成的一个测试工具,在使用CMakeLists.txt文件编译工程的时候,CTest会自动configure、build、test和展现

    2023年04月17日
    浏览(25)
  • Go 工具链详解(四): Golang环境变量设置和查看工具 go env

    go env 是 Go 工具链中的一个命令,用于设置和查看当前 Golang 环境的相关信息,对于理解、编译和运行 Golang 程序非常有用。 go 提供的命令及 go 程序的编译运行都会使用到环境变量,如果未设置对应的环境变量,go 则会使用其默认设置。默认情况下,env 以 shell 脚本(在Windo

    2024年02月16日
    浏览(34)
  • 【Golang】Golang进阶系列教程--Go 语言切片是如何扩容的?

    在 Go 语言中,有一个很常用的数据结构,那就是切片(Slice)。 切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一种引用类型,它有三个属性:指针,长度和容量。 底层源码定义如下: 指针: 指向

    2024年02月14日
    浏览(43)
  • 【Golang】Golang进阶系列教程--Go 语言 map 如何顺序读取?

    Go 语言中的 map 是一种非常强大的数据结构,它允许我们快速地存储和检索键值对。 然而,当我们遍历 map 时,会有一个有趣的现象,那就是输出的键值对顺序是不确定的。 先看一段代码示例: 当我们多执行几次这段代码时,就会发现,输出的顺序是不同的。 首先,Go 语言

    2024年02月14日
    浏览(47)
  • 【Golang】Golang进阶系列教程--Go 语言数组和切片的区别

    在 Go 语言中,数组和切片看起来很像,但其实它们又有很多的不同之处,这篇文章就来说说它们到底有哪些不同。 数组和切片是两个常用的数据结构。它们都可以用于存储一组相同类型的元素,但在底层实现和使用方式上存在一些重要的区别。 Go 中数组的长度是不可改变的

    2024年02月15日
    浏览(45)
  • Golang:Go语言结构

    在我们开始学习 Go 编程语言的基础构建模块前,让我们先来了解 Go 语言最简单程序的结构。 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 表达式 注释 接下来让我们来看下简单的代码,该代码输出了\\\"Hello World!\\\": 让我们来看下以上程序的各个部分: 第一

    2024年02月10日
    浏览(50)
  • 【Golang】go条件编译

    交叉编译只是为了能在一个平台上编译出其他平台可运行的程序,Go 作为一个跨平台的语言,它提供的类库势必也是跨平台的,比如说程序的系统调用相关的功能,能根据所处环境选择对应的源码进行编译。让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,

    2024年02月11日
    浏览(49)
  • 【Golang】go交叉编译

    交叉编译是用来在一个平台上生成另一个平台的可执行程序 。Go 命令集是原生支持交叉编译的。 Mac下编译:Linux 或 Windows 的可执行程序 Linux下编译:Mac 或 Windows的可执行程序 Windows下编译:Mac 或 Linux的可执行程序 需要写一个批处理程序,在里面去设置,因为windows 下的 ter

    2024年02月10日
    浏览(37)
  • 【golang】每日chatGPT:golang中实现ENUM枚举类型 | go enum

    在golang极简的哲学思想中,没有内置枚举类型 这里我们通过map+iota去实现一个枚举类型 枚举值如下: key value 1 发电类 2 储能类 13 负荷类 打印如下: 发电类 储能类 负荷类 ========= 储能类

    2024年02月15日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包