Go 单元测试基本介绍

news2024/11/24 13:30:04

文章目录

    • 引入
    • 一、单元测试基本介绍
      • 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单元测试入门

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Adaboost模型的数据预测和分类matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 AdaBoost(Adaptive Boosting)是一种集成学习方法,由Yoav Freund和Robert Schapire于1995年提出,主要用于提高弱分类…

Docker 学习笔记(九):Docker 网络原理,理解 docker0,虚拟网卡,容器互联,以及跨网络连通

一、前言 记录时间 [2024-4-16] 系列文章简摘: Docker 学习笔记(六):挑战容器数据卷技术一文通,实战多个 MySQL 数据同步,能懂会用,初学必备 Docker 学习笔记(七)&#x…

引领智能互联时代,紫光展锐赋能百业创新发展

随着5G技术的快速发展,各行各业对通信技术的需求也在不断升级。紫光展锐持续深耕5G垂直行业,不断推进5G标准演进,从R15到R16,再到R17,展锐携手生态合作伙伴,不断推出创新性解决方案,在5G RedCap…

FMEA赋能可穿戴设备:打造安全可靠的未来科技新宠!

在科技日新月异的今天,可穿戴设备已成为我们生活中不可或缺的一部分。它们以其便携性、智能化和个性化的特点,深受消费者喜爱。然而,随着可穿戴设备市场的快速扩张,其安全性和可靠性问题也日益凸显。为了确保产品质量,…

【Git】常用命令速查

目录 一、创建版本 二、修改和提交 三、查看提交历史 四、撤销 五、分支与标签 六、合并与衍合 七、远程操作 一、创建版本 命令简要说明注意事项git clone <url>克隆远程版本库 二、修改和提交 命令简要说明注意事项 三、查看提交历史 命令简要说明注意事项 …

Adobe AE(After Effects)2017下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

OpenCV轻松入门(八)——图片卷积

对图像和滤波矩阵进行逐个元素相乘再求和的操作就相当于将一个二维的函数移动到另一个二维函数的所有位置&#xff0c;这个操作就叫卷积。 卷积需要4个嵌套循环&#xff0c;所以它并不快&#xff0c;除非我们使用很小的卷积核。这里一般使用3x3或者5x5 图像滤波 图像滤波是尽…

Map与Set的模拟实现封装

目录 一. 底层原理 二. 红黑树节点的定义 三. 仿函数封装 四. 基本函数的封装 五. 迭代器的封装 5.1 迭代器的基本定义 5.2 *与->操作 5.3 迭代器的操作 5.3.1 右子树不为空 5.3.2 右子树为空 5.4 迭代器的--操作 5.4.1 当前节点的父节点…

CentOS 7开机启动过程,引导和服务,密码的修改

开机启动过程&#xff1a; 引导过程&#xff1a;1.开机自检(BIOS)->2.MBR引导->GRUB菜单->加载内核kernel->systemd进程初始化 程序&#xff1a;执行特定任务的一串代码&#xff0c;静态&#xff0c;存在硬盘中。 进程&#xff1a;运行中的程序叫进程&#xff0…

第十一章数据仓库和商务智能10分

【数据仓库-后端&#xff0c;商务智能-前端】 基本算法&#xff1a;关联关系&#xff08;牵手-谈恋爱&#xff09;&#xff0c;集群关系&#xff08;杭州人爱吃酸甜口&#xff09;&#xff0c;决策树&#xff0c;线性回归&#xff0c;贝叶斯&#xff0c;神经网络&#xff0c;时…

【Linux】磁盘扩容到根目录逻辑卷(LVM)

目录 一、物理卷和逻辑卷 1.物理卷和逻辑卷的区别 2.在Linux系统中查看所有物理卷的信息 3.在Linux系统中查看所有逻辑卷的信息 二、文件系统 三、实操-对root&#xff08;/&#xff09;目录进行扩容 1.使用lsblk命令查看新加入的磁盘信息 2.fdisk -l命令查看系统中磁盘…

景区导览系统平台|智能导览|数字人导游|VR游园

随着人工智能、元宇宙等技术的飞速发展&#xff0c;文旅行业正迎来一场前所未有的变革。道可云文旅元宇宙平台以其独特的智慧景区导览系统、元宇宙空间以及数字人导游等创新应用&#xff0c;为景区和游客带来了全新的旅游体验&#xff0c;也标志着文旅行业正式步入了元宇宙时代…

含多种需求响应及电动汽车的微网/虚拟电厂日前优化调度

1 主要内容 程序主要建立一个微网/虚拟电厂的日前优化调度模型&#xff0c;以燃气轮机运行成本、购售电费用、电动汽车电池损耗成本以及需求响应费用之和为目标&#xff0c;在日前经济调度模型中&#xff0c;加入了电动汽车模型&#xff0c;考虑了电动汽车出行规律以及充放电规…

华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理工具

文章目录 华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理工具1. 介绍2. 下载3. 静音模式、平衡模式、增强模式配置4. 配置电源方案与模式切换绑定5. 启动Ghelper控制面板6. 目前支持的设备型号 华硕ROG幻16笔记本电脑模式切换管理工具完美替代华硕奥创中心管理…

环境搭建创建项目_使用DevEco开发工具进行开发_创建项目_认识项目结构---HarmonyOS4.0+鸿蒙NEXT工作笔记001

首先去下载DevEco Studio然后再去安装就可以了 安装下一步下一步非常简单 首先去安装nodejs,可以看到,有两个安装方法,左边是自己安装的制定文件夹就可以了,然后 右边是使用鸿蒙自带的,我们选择第二个 然后我们看这个ohpm其实就跟npm是一个意思,用来管理鸿蒙的包的. 这里我们…

JavaEE:JVM

基本介绍 JVM&#xff1a;Java虚拟机&#xff0c;用于解释执行Java字节码 jdk&#xff1a;Java开发工具包 jre&#xff1a;Java运行时环境 C语言将写入的程序直接编译成二进制的机器语言&#xff0c;而java不想重新编译&#xff0c;希望能直接执行。Java先通过javac把.java…

【机器学习】贝叶斯算法在机器学习中的应用与实例分析

贝叶斯算法在机器学习中的应用与实例分析 一、贝叶斯算法原理及重要性二、朴素贝叶斯分类器的实现三、贝叶斯网络在自然语言处理中的应用四、总结与展望 在人工智能的浪潮中&#xff0c;机器学习以其独特的魅力引领着科技领域的创新。其中&#xff0c;贝叶斯算法以其概率推理的…

用于密集视觉冲击的紧凑三维高斯散射Compact 3D Gaussian Splatting For Dense Visual SLAM

Compact 3D Gaussian Splatting For Dense Visual SLAM 用于密集视觉冲击的紧凑三维高斯散射 Tianchen Deng 邓天辰11Yaohui Chen 陈耀辉11Leyan Zhang 张乐妍11Jianfei Yang 杨健飞22Shenghai Yuan 圣海元22Danwei Wang 王丹伟22Weidong Chen 陈卫东11 Abstract 摘要 …

通过腾讯云搭建跨境电商demo的详细操作过程(建站系统 保姆级指导,巨详细)

引言&#xff1a; 有许多做跨境电商的朋友&#xff0c;或者为跨境电商服务的小企业&#xff0c;都会面临搭建电商平台V1.0的问题 因此&#xff0c;花了点时间&#xff0c;找了一个开源的项目&#xff0c;让大家可以跑起来&#xff0c;一方面了解平台都有哪些模块&#xff0c;另…

Unity 左右折叠显示与隐藏UI的简单实现

要实现一个简单的UI左右折叠显示与隐藏&#xff0c;可以结合遮罩&#xff0c;通过代码控制UI区块的宽度和位移来实现。 具体可以按以下步骤实现&#xff1a; 1、新建一个Image组件&#xff0c;并添加精灵&#xff0c;调整大小后&#xff0c;复制一份作为该UI的父物体&#xf…