Go 单元测试基本介绍

文章目录

    • 引入
    • 一、单元测试基本介绍
      • 1.1 什么是单元测试?
      • 1.2 如何写好单元测试
      • 1.3 单元测试的优点
      • 1.4 单元测试的设计原则
    • 二、Go语言测试
      • 2.1 Go单元测试概要
      • 2.2 Go单元测试基本规范
      • 2.3 一个简单例子
        • 2.3.1 使用Goland 生成测试文件
        • 2.3.2 运行单元测试
        • 2.3.3 完善测试用例
        • 2.3.5 回归测试
      • 2.4 Goland 直接运行单元测试
      • 2.5 Go Test 命令参数
      • 2.6 运行一个文件中的单个测试
      • 2.7 测试覆盖率
      • 2.8 公共的帮助函数(helpers)
    • 三、`testing.T`的拥有的方法
    • 四、Table Driven 模式
      • 4.1 介绍
      • 4.2 Go 组织测试的方式
      • 4.3 举个例子
      • 4.4 运行 Table Driven 下的单个测试
    • 五、`testify/assert` 断言工具包
      • 5.1 介绍
      • 5.2 安装
      • 5.3 使用
    • 六、单元测试代码模板
    • 七、参考文档

引入

正常的业务开发之后的测试流程,都是先单元测试,后集成测试。

  • 单元测试:针对每一个方法进行的测试,单独验证每一个方法的正确性。
  • 集成测试:多个组件合并在一起的测试,验证各个方法、组件之间配合无误。

所以一般项目都是开发人员要先搞单元测试,单元测试初步验证之后,再集成测试。

单元测试验证了各个方法的基本逻辑之后,集成测试就比较少问题了。

一、单元测试基本介绍

1.1 什么是单元测试?

单元测试(Unit Tests, UT) 是一个优秀项目不可或缺的一部分,是对软件中的最小可测试部分进行检查和验证。在面向对象编程中,最小测试单元通常是一个方法或函数。单元测试通常由开发者编写,用于验证代码的一个很小的、很具体的功能是否正确。单元测试是自动化测试的一部分,可以频繁地运行以检测代码的更改是否引入了新的错误。

特别是在一些频繁变动和多人合作开发的项目中尤为重要。你或多或少都会有因为自己的提交,导致应用挂掉或服务宕机的经历。如果这个时候你的修改导致测试用例失败,你再重新审视自己的修改,发现之前的修改还有一些特殊场景没有包含,恭喜你减少了一次上库失误。也会有这样的情况,项目很大,启动环境很复杂,你优化了一个函数的性能,或是添加了某个新的特性,如果部署在正式环境上之后再进行测试,成本太高。对于这种场景,几个小小的测试用例或许就能够覆盖大部分的测试场景。而且在开发过程中,效率最高的莫过于所见即所得了,单元测试也能够帮助你做到这一点,试想一下,假如你一口气写完一千行代码,debug 的过程也不会轻松,如果在这个过程中,对于一些逻辑较为复杂的函数,同时添加一些测试用例,即时确保正确性,最后集成的时候,会是另外一番体验。

1.2 如何写好单元测试

首先,学会写测试用例。比如如何测试单个函数/方法;比如如何做基准测试;比如如何写出简洁精炼的测试代码;再比如遇到数据库访问等的方法调用时,如何 mock

然后,写可测试的代码。高内聚,低耦合是软件工程的原则,同样,对测试而言,函数/方法写法不同,测试难度也是不一样的。职责单一,参数类型简单,与其他函数耦合度低的函数往往更容易测试。我们经常会说,“这种代码没法测试”,这种时候,就得思考函数的写法可不可以改得更好一些。为了代码可测试而重构是值得的。

1.3 单元测试的优点

单元测试讲究的是快速测试、快速修复。

  • 测试该环节中的业务问题,比如说在写测试的时候,发现业务流程设计得不合理。
  • 测试该环节中的技术问题,比如说nil之类的问题。

单元测试,从理论上来说,你不能依赖任何第三方组件。也就是说,你不能使用MySQL或者Redis

如图,要快速启动测试,快速发现BUG,快速修复,快速重测。

1.4 单元测试的设计原则

  1. 每个测试单元必须完全独立、能单独运行。
  2. 一个测试单元应只关注一个功能函数,证明它是正确的;
  3. 测试代码要能够快速执行。
  4. 不能为了单元测试而修改已完成的代码在编写代码后执行针对本次的单元测试,并执行之前的单元测试用例。
  5. 以保证你后来编写的代码不会破坏任何事情;
  6. 单元测试函数使用长的而且具有描述性的名字,例如都以test_开头,然后加上具体的函数名字或者功能描述;例如:func_test.go。
  7. 测试代码必须具有可读性。

二、Go语言测试

2.1 Go单元测试概要

Go 语言的单元测试默认采用官方自带的测试框架,通过引入 testing 包以及 执行 go test 命令来实现单元测试功能。

在源代码包目录内,所有以 _test.go 为后缀名的源文件会被 go test 认定为单元测试的文件,这些单元测试的文件不会包含在 go build 的源代码构建中,而是单独通过 go test 来编译并执行。

2.2 Go单元测试基本规范

Go 单元测试的基本规范如下:

  • 每个测试函数都必须导入 testing 包。测试函数的命名类似func TestName(t *testing.T),入参必须是 *testing.T
  • 测试函数的函数名必须以大写的 Test 开头,后面紧跟的函数名,要么是大写开关,要么就是下划线,比如 func TestName(t *testing.T) 或者 func Test_name(t *testing.T) 都是 ok 的, 但是 func Testname(t *testing.T)不会被检测到
  • 通常情况下,需要将测试文件和源代码放在同一个包内。一般测试文件的命名,都是 {source_filename}_test.go,比如我们的源代码文件是allen.go ,那么就会在 allen.go 的相同目录下,再建立一个 allen_test.go 的单元测试文件去测试 allen.go 文件里的相关方法。

当运行 go test 命令时,go test 会遍历所有的 *_test.go 中符合上述命名规则的函数,然后生成一个临时的 main 包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理测试中生成的临时文件。

2.3 一个简单例子

2.3.1 使用Goland 生成测试文件

我们来创建一个示例,创建名为 add.go的文件

package main

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

这里借助Goland给 ADD 函数生成并且编写测试用例,只需要右键点击函数,转到Generate -> Test for file function(生成函数测试)。

Goland 为我们生成了add_test.go单测文件

package main

import "testing"

func TestAdd(t *testing.T) {
	type args struct {
		a int
		b int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Add(tt.args.a, tt.args.b); got != tt.want {
				t.Errorf("Add() = %v, want %v", got, tt.want)
			}
		})
	}
}
2.3.2 运行单元测试

运行 go test,该 package 下所有的测试用例都会被执行。

go test .                                                
ok      gotest  1.060s

go test -v-v 参数会显示每个用例的测试结果,另外 -cover 参数可以查看覆盖率。

go test -v                                               
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      gotest  1.208s
2.3.3 完善测试用例

接着我们来完善上面的测试用例,代码如下:

package main

import "testing"

func TestAdd(t *testing.T) {
	type args struct {
		a int
		b int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		{
			name: "Adding positive numbers",
			args: args{a: 2, b: 3},
			want: 5,
		},
		{
			name: "Adding negative numbers",
			args: args{a: -2, b: -3},
			want: -5,
		},
		{
			name: "Adding positive and negative numbers",
			args: args{a: 2, b: -3},
			want: -1,
		},
		{
			name: "Adding zero",
			args: args{a: 2, b: 0},
			want: 2,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Add(tt.args.a, tt.args.b); got != tt.want {
				t.Errorf("Add() = %v, want %v", got, tt.want)
			}
		})
	}
}
2.3.5 回归测试

我们修改了代码之后仅仅执行那些失败的测试用例或新引入的测试用例是错误且危险的,正确的做法应该是完整运行所有的测试用例,保证不会因为修改代码而引入新的问题。

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Adding_positive_numbers
=== RUN   TestAdd/Adding_negative_numbers
=== RUN   TestAdd/Adding_positive_and_negative_numbers
=== RUN   TestAdd/Adding_zero
--- PASS: TestAdd (0.00s)
    --- PASS: TestAdd/Adding_positive_numbers (0.00s)
    --- PASS: TestAdd/Adding_negative_numbers (0.00s)
    --- PASS: TestAdd/Adding_positive_and_negative_numbers (0.00s)
    --- PASS: TestAdd/Adding_zero (0.00s)
=== RUN   TestMul
=== RUN   TestMul/结果为0
=== RUN   TestMul/结果为-1
=== RUN   TestMul/结果为1
--- PASS: TestMul (0.00s)
    --- PASS: TestMul/结果为0 (0.00s)
    --- PASS: TestMul/结果为-1 (0.00s)
    --- PASS: TestMul/结果为1 (0.00s)
PASS
ok      gotest  0.912s

测试结果表明我们的单元测试全部通过。

2.4 Goland 直接运行单元测试

如果你的测试方法签名没错的话,就能看到这个绿色图标,点击就能看到很多选项。

最主要的是:

  • Run:运行模式,直接运行整个测试。
  • Debug:Debug模式,你可以打断点。
  • Run xxx with Coverage:运行并且输出测试覆盖率。
  • 其它Profile都是性能分析,很少用。

除非你要看测试覆盖率,不然都用Debug

2.5 Go Test 命令参数

go test 是 Go 语言的测试工具,你可以使用它来运行 Go 程序的测试函数。

你可以在命令行中使用以下参数来调用 go test 命令:

  • -run:指定要运行的测试函数的名称的正则表达式。例如,使用 go test -run TestAdd 可以运行名称为 TestSum 的测试函数。
  • -bench:指定要运行的基准测试的名称的正则表达式。例如,使用 go test -bench . 可以运行所有基准测试。
  • -count:指定要运行测试函数或基准测试的次数。例如,使用 go test -count 2 可以运行测试函数或基准测试两次。
  • -v:输出测试函数或基准测试的详细输出。
  • -timeout:设置测试函数或基准测试的超时时间。例如,使用 go test -timeout 1s 可以将超时时间设置为 1 秒。

以下是一个go Test命令表格:

参数说明
-bench regexp仅运行与正则表达式匹配的基准测试。默认不运行任何基准测试。使用 -bench .-bench= 来运行所有基准测试。
-benchtime t运行每个基准测试足够多的迭代,以达到指定的时间 t(例如 -benchtime 1h30s)。默认为1秒(1s)。特殊语法 Nx 表示运行基准测试 N 次(例如 -benchtime 100x)。
-count n运行每个测试、基准测试和模糊测试 n 次(默认为1次)。如果设置了 -cpu,则为每个 GOMAXPROCS 值运行 n 次。示例总是运行一次。-count 不适用于通过 -fuzz 匹配的模糊测试。
-cover启用覆盖率分析。
-covermode set,count,atomic设置覆盖率分析的 mode。默认为 “set”,如果启用了 -race,则为 “atomic”。
-coverpkg pattern1,pattern2,pattern3对匹配模式的包应用覆盖率分析。默认情况下,每个测试仅分析正在测试的包。
-cpu 1,2,4指定一系列的 GOMAXPROCS 值,在这些值上执行测试、基准测试或模糊测试。默认为当前的 GOMAXPROCS 值。-cpu 不适用于通过 -fuzz 匹配的模糊测试。
-failfast在第一个测试失败后不启动新的测试。
-fullpath在错误消息中显示完整的文件名。
-fuzz regexp运行与正则表达式匹配的模糊测试。当指定时,命令行参数必须精确匹配主模块中的一个包,并且正则表达式必须精确匹配该包中的一个模糊测试。
-fuzztime t在模糊测试期间运行足够多的模糊目标迭代,以达到指定的时间 t(例如 -fuzztime 1h30s)。默认为永远运行。特殊语法 Nx 表示运行模糊目标 N 次(例如 -fuzztime 1000x)。
-fuzzminimizetime t在每次最小化尝试期间运行足够多的模糊目标迭代,以达到指定的时间 t(例如 -fuzzminimizetime 30s)。默认为60秒。特殊语法 Nx 表示运行模糊目标 N 次(例如 -fuzzminimizetime 100x)。
-json以 JSON 格式记录详细输出和测试结果。这以机器可读的格式呈现 -v 标志的相同信息。
-list regexp列出与正则表达式匹配的测试、基准测试、模糊测试或示例。不会运行任何测试、基准测试、模糊测试或示例。
-parallel n允许并行执行调用 t.Parallel 的测试函数,以及运行种子语料库时的模糊目标。此标志的值是同时运行的最大测试数。
-run regexp仅运行与正则表达式匹配的测试、示例和模糊测试。
-short告诉长时间运行的测试缩短其运行时间。默认情况下是关闭的,但在 all.bash 中设置,以便在安装 Go 树时可以运行健全性检查,但不花费时间运行详尽的测试。
-shuffle off,on,N随机化测试和基准测试的执行顺序。默认情况下是关闭的。如果 -shuffle 设置为 on,则使用系统时钟种子随机化器。如果 -shuffle 设置为整数 N,则 N 将用作种子值。在这两种情况下,种子将报告以便复现。
-skip regexp仅运行与正则表达式不匹配的测试、示例、模糊测试和基准测试。
-timeout d如果测试二进制文件运行时间超过持续时间 d,则发生 panic。如果 d 为0,则禁用超时。默认为10分钟(10m)。
-v详细输出:记录所有运行的测试。即使测试成功,也打印所有来自 LogLogf 调用的文本。
-vet list配置在 “go test” 期间对 “go vet” 的调用,以使用由逗号分隔的 vet 检查列表。如果列表为空,“go test” 使用被认为总是值得解决的精选检查列表运行 “go vet”。如果列表为

更多可以参考 Go 语言的官方文档或使用 go help test 命令查看帮助信息

2.6 运行一个文件中的单个测试

如果只想运行其中的一个用例,例如 TestAdd,可以用 -run 参数指定,该参数支持通配符 *,和部分正则表达式,例如 ^$

go test -run TestAdd -v
=== RUN   TestAdd
=== RUN   TestAdd/Adding_positive_numbers
=== RUN   TestAdd/Adding_negative_numbers
=== RUN   TestAdd/Adding_positive_and_negative_numbers
=== RUN   TestAdd/Adding_zero
--- PASS: TestAdd (0.00s)
    --- PASS: TestAdd/Adding_positive_numbers (0.00s)
    --- PASS: TestAdd/Adding_negative_numbers (0.00s)
    --- PASS: TestAdd/Adding_positive_and_negative_numbers (0.00s)
    --- PASS: TestAdd/Adding_zero (0.00s)
PASS
ok      gotest  1.008s

2.7 测试覆盖率

测试覆盖率是指代码被测试套件覆盖的百分比。通常我们使用的都是语句的覆盖率,也就是在测试中至少被运行一次的代码占总代码的比例。在公司内部一般会要求测试覆盖率达到80%左右。

Go提供内置功能来检查你的代码覆盖率,即使用go test -cover来查看测试覆盖率。

go test -cover
PASS
coverage: 100.0% of statements
ok      gotest  1.381s

还可以使用 -coverprofile 标志将覆盖率数据输出到一个文件中,然后使用 go tool cover 命令来查看更详细的覆盖率报告。

2.8 公共的帮助函数(helpers)

对一些重复的逻辑,抽取出来作为公共的帮助函数(helpers),可以增加测试代码的可读性和可维护性。 借助帮助函数,可以让测试用例的主逻辑看起来更清晰。

例如,我们可以将创建多次使用的逻辑抽取出来:

type addCase struct{ A, B, want int }

func createAddTestCase(t *testing.T, c *addCase) {
	// t.Helper()
	if ans := Add(c.A, c.B); ans != c.want {
		t.Fatalf("%d * %d expected %d, but %d got",
			c.A, c.B, c.want, ans)
	}

}

func TestAdd2(t *testing.T) {
	createAddTestCase(t, &addCase{1, 1, 2})
	createAddTestCase(t, &addCase{2, -3, -1})
	createAddTestCase(t, &addCase{0, -1, 0}) // wrong case
}

在这里,我们故意创建了一个错误的测试用例,运行 go test,用例失败,会报告错误发生的文件和行号信息:

go test
--- FAIL: TestAdd2 (0.00s)
    add_test.go:109: 0 * -1 expected 0, but -1 got
FAIL
exit status 1
FAIL    gotest  1.090s

可以看到,错误发生在第11行,也就是帮助函数 createAddTestCase 内部。116, 117, 118行都调用了该方法,我们第一时间并不能够确定是哪一行发生了错误。有些帮助函数还可能在不同的函数中被调用,报错信息都在同一处,不方便问题定位。因此,Go 语言在 1.9 版本中引入了 t.Helper(),用于标注该函数是帮助函数,报错时将输出帮助函数调用者的信息,而不是帮助函数的内部信息。

修改 createAddTestCaseV1,调用 t.Helper()

type addCaseV1 struct {
	name string
	A, B int
	want int
}

func createAddTestCaseV1(c *addCaseV1, t *testing.T) {
	t.Helper()
	t.Run(c.name, func(t *testing.T) {
		if ans := Add(c.A, c.B); ans != c.want {
			t.Fatalf("%s: %d + %d expected %d, but %d got",
				c.name, c.A, c.B, c.want, ans)
		}
	})
}

func TestAddV1(t *testing.T) {
	createAddTestCaseV1(&addCaseV1{"case 1", 1, 1, 2}, t)
	createAddTestCaseV1(&addCaseV1{"case 2", 2, -3, -1}, t)
	createAddTestCaseV1(&addCaseV1{"case 3", 0, -1, 0}, t)
}

运行 go test,报错信息如下,可以非常清晰地知道,错误发生在第 131 行。

go test
--- FAIL: TestAddV1 (0.00s)
    --- FAIL: TestAddV1/case_3 (0.00s)
        add_test.go:131: case 3: 0 + -1 expected 0, but -1 got
FAIL
exit status 1
FAIL    gotest  0.434s

关于 helper 函数的 2 个建议:

  • 不要返回错误, 帮助函数内部直接使用 t.Errort.Fatal 即可,在用例主逻辑中不会因为太多的错误处理代码,影响可读性。
  • 调用 t.Helper() 让报错信息更准确,有助于定位。

当然,如果你是用Goland 编辑器的话,可以不使用t.Helper(),自动会帮你打印出错误详细信息

三、testing.T的拥有的方法

以下是提供的 *testing.T 类型的方法及其用途的注释:

// T 是 Go 语言测试框架中的一个结构体类型,它提供了用于编写测试的方法。
// 它通常通过测试函数的参数传递给测试函数。

// Cleanup 注册一个函数,该函数将在测试结束时执行,用于清理测试过程中创建的资源。
func (c *T) Cleanup(func())

// Error 记录一个错误信息,但不会立即停止测试的执行。
func (c *T) Error(args ...interface{})

// Errorf 根据 format 和 args 记录一个格式化的错误信息,但不会立即停止测试的执行。
func (c *T) Errorf(format string, args ...interface{})

// Fail 标记测试函数为失败,但不会停止当前测试的执行。
func (c *T) Fail()

// FailNow 标记测试函数为失败,并立即停止当前测试的执行。
func (c *T) FailNow()

// Failed 检查测试是否失败。
func (c *T) Failed() bool

// Fatal 记录一个错误信息,并立即停止测试的执行。
func (c *T) Fatal(args ...interface{})

// Fatalf 记录一个格式化的错误信息,并立即停止测试的执行。
func (c *T) Fatalf(format string, args ...interface{})

// Helper 标记当前函数为辅助函数,当测试失败时,辅助函数的文件名和行号将不会显示在错误消息中。
func (c *T) Helper()

// Log 记录一些信息,这些信息只有在启用详细日志(-v标志)时才会显示。
func (c *T) Log(args ...interface{})

// Logf 记录一些格式化的信息,这些信息只有在启用详细日志(-v标志)时才会显示。
func (c *T) Logf(format string, args ...interface{})

// Name 返回当前测试或基准测试的名称。
func (c *T) Name() string

// Skip 标记测试为跳过,并记录一个错误信息。
func (c *T) Skip(args ...interface{})

// SkipNow 标记测试为跳过,并立即停止当前测试的执行。
func (c *T) SkipNow()

// Skipf 标记测试为跳过,并记录一个格式化的错误信息。
func (c *T) Skipf(format string, args ...interface{})

// Skipped 检查测试是否被跳过。
func (c *T) Skipped() bool

// TempDir 返回一个临时目录的路径,该目录在测试结束时会被自动删除。
func (c *T) TempDir() string

四、Table Driven 模式

4.1 介绍

Table Driven 模式是一种软件设计模式,它通过将测试数据存储在一个表格(通常是结构化的数据结构,如数组、切片、映射或结构体)中,然后在一个单独的函数或方法中遍历这个表格来执行测试。这种模式使得测试代码更加模块化、可读性和可维护性更高。

在 Go 语言中,Table Driven 模式通常通过定义一个结构体来组织测试数据,然后使用一个循环来遍历这个结构体,为每个测试用例执行相同的测试逻辑。这种方法可以很容易地添加新的测试用例,并且可以使测试代码更加简洁和易于维护。

4.2 Go 组织测试的方式

Go里面,惯常的组织测试的方式,都是用Table Driven

Table Driven的形式如下图。主要分成三个部分:

  • 测试用例的定义:即每一个测试用例需要有什么。
  • 具体的测试用例:你设计的每一个测试用例都在这里。
  • 执行测试用例:这里面还包括了对测试结果进行断言。

注意,你要优先使用Table Driven,但是不用强求

你把测试用例定义看做是列名,每一个测试用例就是一行数据,就能理解Table Driven这个含义了。

4.3 举个例子

func TestMul(t *testing.T) {
	type args struct {
		a int
		b int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		{
			name: "结果为0",
			args: args{a: 2, b: 0},
			want: 0,
		},
		{
			name: "结果为-1",
			args: args{a: -1, b: 1},
			want: -1,
		},
		{
			name: "结果为1",
			args: args{a: -1, b: -1},
			want: 1,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Mul(tt.args.a, tt.args.b); got != tt.want {
				t.Errorf("Mul() = %v, want %v", got, tt.want)
			}
		})
	}
}

4.4 运行 Table Driven 下的单个测试

当你使用前面 Table Driven 的模式时,可以单个运行测试用例

五、testify/assert 断言工具包

5.1 介绍

testify/assert 是一个流行的Go语言断言库,它提供了一组丰富的断言函数,用于简化测试代码的编写。这个库提供了一种更声明式的方式来编写测试,使得测试意图更加明确,代码更加简洁。

使用 testify/assert 时,您不再需要编写大量的 if 语句和 Error 方法调用来检查条件和记录错误。相反,您可以使用像 assert.Equalassert.Nilassert.True 这样的断言函数来验证测试的期望结果。

5.2 安装

go get github.com/stretchr/testify

5.3 使用

断言包提供了一些有用的方法,可以帮助您在Go语言中编写更好的测试代码。

  • 打印友好、易于阅读的失败描述
  • 允许编写可读性强的代码
  • 可以为每个断言添加可选的注释信息
    看看它的实际应用:
package yours
import (
  "testing"
  "github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
  // 断言相等
  assert.Equal(t, 123, 123, "它们应该相等")
  // 断言不等
  assert.NotEqual(t, 123, 456, "它们不应该相等")
  // 断言为nil(适用于错误处理)
  assert.Nil(t, object)
  // 断言不为nil(当你期望得到某个结果时使用)
  if assert.NotNil(t, object) {
    // 现在我们知道object不是nil,我们可以安全地进行
    // 进一步的断言而不会引起任何错误
    assert.Equal(t, "Something", object.Value)
  }
}

每个断言函数都接受 testing.T 对象作为第一个参数。这就是它如何通过正常的Go测试能力输出错误信息的方式。

每个断言函数都返回一个布尔值,指示断言是否成功。这对于在特定条件下继续进行进一步的断言非常有用。

当我们有多个断言语句时,还可以使用assert := assert.New(t)创建一个assert对象,它拥有前面所有的断言方法,只是不需要再传入Testing.T参数了。

package yours
import (
  "testing"
  "github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
  assert := assert.New(t)
  // 断言相等
  assert.Equal(123, 123, "它们应该相等")
  // 断言不等
  assert.NotEqual(123, 456, "它们不应该相等")
  // 断言为nil(适用于错误处理)
  assert.Nil(object)
  // 断言不为nil(当你期望得到某个结果时使用)
  if assert.NotNil(object) {
    // 现在我们知道object不是nil,我们可以安全地进行
    // 进一步的断言而不会引起任何错误
    assert.Equal("Something", object.Value)
  }
}

在上面的示例中,assert.New(t) 创建了一个新的 assert 实例,然后您可以使用这个实例的方法来进行断言。如果断言失败,testify/assert 会自动标记测试为失败,并记录一个详细的错误消息。

六、单元测试代码模板

func Test_Function(t *testing.T) {
	testCases := []struct {
		name string //测试用例的名称
		args any    //测试用例的输入参数
		want string //期望的返回值
	}{
		// 测试用例,测试用例表格
		{},
		{},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			//具体的测试代码
		})
	}
}

七、参考文档

  • Go Test 单元测试简明教程
  • Go单元测试入门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/558008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

存储过程的使用(一)

目录 不带参数的存储过程 创建一个存储过程,向数据表 dept 中插入一条记录 带 IN 参数的存储过程 在存储过程中接受来自外部的数值,在存储过程中判断该数值是否大于零并显示 输入一个编号,查询数据表emp中是否有这个编号,如果…

博客系统项目测试(selenium+Junit5)

在做完博客系统项目之后,需要对项目的功能、接口进行测试,利用测试的工具:selenium以及Java的单元测试工具Junit进行测试,下面式测试的思维导图,列出该项目需要测试的所有测试用例: 测试结果(全…

【Tesla T4为例】GPU安装最新版本NVIDIA Driver、CUDA、cuDNN、Anaconda、Pytorch

NVIDIA Driver 进入英伟达官网下载页面 按照以上方式选择即可得到>535.113.01版本的驱动,可以实现多卡推理,小于这个版本会导致多卡训练以及推理报错 虽然最新版本为550.54.15,但是535版本更加稳定,并且pytorch目前只支持到1…

云渲染采用了哪些核心技术来实现其高效的计算的?

云渲染运用云计算技术,将3D渲染任务分配至远程服务器集群以实现高速高效渲染,释放本地资源,缩短了影视动画、效果图等的制作周期,在影视、建筑、游戏等行业发挥关键作用。哪云渲染都用了哪些技术呢?我们一起来看看。 …

2024新版淘宝客PHP网站源码

源码介绍 2024超好看的淘客PHP网站源码,可以做优惠券网站,上传服务器,访问首页进行安装 安装好了之后就可以使用了,将里面的信息配置成自己的就行 喜欢的朋友们拿去使用把 效果截图 源码下载 2024新版淘宝客网站源码

UE5下载与安装

官方网站:https://www.unrealengine.com/zh-CN 1、下载启动程序安装包。 登录官网后,点击首页右侧下载按钮下载Epic Games启动程序的安装包,如下图: 2、安装启动程序。 双击步骤1所下载安装软件,如下图:…

一个开箱即用的物联网项目,开源免费可商用

一、平台简介 今天给大家推荐一款开源的物联网项目,简单易用,非常适合中小团队和个人使用,项目代码和文档完全开源,个人和公司都可以应用于商业项目,只需要保留开源协议文件即可。 本项目可应用于智能家居、农业监测…

Jmeter测试学习笔记

第一章 jmeter基础知识 一.Jmeter工具中的组件 1.测试计划:Jmeter测试的起点。容器。 2.线程组:代表一定的用户 3.取样器:发送请求的最小单元 4.逻辑控制器:处理请求逻辑 5.前置处理器:请求之前的操作 6.后置处…

算法课程笔记——pair的使用

先思考&#xff0c;为什么 STL 中的容器和算法都是用的左闭右开区间&#xff1f; | | | 这样迭代器只需要支持和!(或者<或者)操作就可以方便的进行区间遍历了。 其它区间设置的话&#xff0c;要么得支持<操作&#xff0c;要么得在循环体内&#xff0c;操作之前进行!判定。…

Proxmox VE 实现批量增加多网络

前言 实现批量创建多网络&#xff0c;更改主机名称&#xff0c;hosts解析 初始化网卡&#xff0c;主机名称&#xff0c;hosts解析&#xff0c;重启网卡 我的主机六个网卡&#xff0c;使用的有四个网卡&#xff0c;以下一键创建和初始化主机名称我是以硬件的SN号最为主机的名…

【InternLM 实战营第二期作业04】XTuner微调LLM:1.8B、多模态、Agent

基础作业 训练自己的小助手认知 1.环境安装 安装XTuner 源码 # 如果你是在 InternStudio 平台&#xff0c;则从本地 clone 一个已有 pytorch 的环境&#xff1a; # pytorch 2.0.1 py3.10_cuda11.7_cudnn8.5.0_0studio-conda xtuner0.1.17 # 如果你是在其他平台&#x…

[NISACTF 2022]huaji?

注意要加--run-asroot

第四百六十七回

文章目录 1. 知识回顾2. 使用方法3. 示例代码4. 内容总结 我们在上一章回中介绍了"OverlayEntry组件简介"相关的内容&#xff0c;本章回中将介绍OverlayEntry组件的用法.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 知识回顾 我们在上一章回中介绍了Overlay…

高通 Android 12 源码编译aidl接口

最近在封装系统sdk接口 于是每次需要更新aidl接口 &#xff0c;传统方式一般使用make update-api或者修改Android.mk文件&#xff0c;今天我尝试使用Android.bp修改 &#xff0c;Android 10之前在Android.mk文件修改&#xff0c;这里不做赘述。下面开始尝试修改&#xff0c;其实…

CTFHub(web sql注入)(二)

布尔盲注 盲注原理&#xff1a; 将自己的注入语句使用and与?id1并列&#xff0c;完成注入 手工注入&#xff1a; 爆库名长度 首先通过折半查找的方法&#xff0c;通过界面的回显结果找出数据库名字的长度&#xff0c;并通过相同的方法依次找到数据库名字的每个字符、列名…

ROS 2边学边练(29)-- 使用替换机制

前言 启动文件用于启动节点、服务和执行流程。这组操作可能有影响其行为的参数。替换机制可以在参数中使用&#xff0c;以便在描述可重复使用的启动文件时提供更大的灵活性。替换是仅在执行启动描述期间评估的变量&#xff0c;可用于获取特定信息&#xff0c;如启动配置、环境变…

2024年哪一款洗地机好用?四大热门主流机型分享

传统的拖地方式必须是拖一会就得清洗一遍拖把&#xff0c;如果房屋面积大&#xff0c;中途得经历无数次换清水的过程&#xff0c;而且拖地是得频繁得弯腰用力气&#xff0c;顽固的污渍还需要来回反复拖几遍&#xff0c;甚至要蹲下身子手动抹布清洁&#xff0c;真的是费时费力。…

【科研入门】评价指标AUC原理及实践

评价指标AUC原理及实践 目录 评价指标AUC原理及实践一、二分类评估指标1.1 混淆矩阵1.2 准确率 Accuracy定义公式局限性 1.3 精确率 Precision 和 召回率 Recall定义公式 1.4 阈值定义阈值的调整 1.5 ROC与AUC引入定义公式理解AUC算法 一、二分类评估指标 1.1 混淆矩阵 对于二…

脾虚百病生,出现这3种情况,说明是脾虚了,简单2步养出好脾胃~

中医认为脾胃为后天之本&#xff0c;人体通过脾胃来消化吸收营养物质&#xff0c;脾主运化水谷精微、运化水湿&#xff0c;脾主肌肉&#xff0c;脾主生血、统血&#xff0c;为气血生化之源&#xff0c;是人体气机升降的枢纽。 脾虚百病生 李东垣在《脾胃论》说&#xff1a;“内…

Python CSV数据处理工具库之clevercsv使用详解

概要 CSV(Comma-Separated Values)是一种常见的数据格式,用于存储和传输表格数据。Python clevercsv库是一个强大的CSV数据处理工具,提供了丰富的特性和功能,帮助用户高效处理CSV文件。 安装 要安装Python clevercsv库,可以使用pip工具进行安装: pip install cleverc…