马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
承上启下
在Go语言中,我们写了代码之后常常就要举行测试。我们可以直接在go函数中调用详细的函数,从而实现测试的目标。但是一旦体系复杂的环境下,我们频仍修改main调用函数就显得不太正常了。那么是不是存在一种方法,让我们可以捏造一些数据举行测试,而且只测试一个单一函数的功能呢?Go内置了一个test库,本日我们学习一下这个库怎么利用把。
开始学习
在Go语言中,测试是开发过程的一个告急构成部分。Go内置了一套强盛的测试框架,使得编写单元测试和基准测试变得简单快捷。以下是关于Go语言测试的先容,包罗testing库和基准测试(benchmark)。
测试文件定名规范
Go语言的测试文件通常与被测试的代码放在同一包中,而且文件名以_test.go末了。比方,假如我们要为math包中的add.go文件编写测试,测试文件应该定名为add_test.go。
单元测试
什么是单元测试
单元测试是指对软件中的最小可测试部分举行查抄。在面向对象编程中,这通常指的是单个方法或函数;在过程式编程中,则大概是一个过程或函数。单元测试的目标是验证这个单元是否精确实验了预定的使命,而且没故不测的副作用。
单元测试的步调
单元测试用于验证代码的各个部分是否按预期工作。以下是编写单元测试的根本步调:
- 导入testing包:全部测试代码都须要导入testing包。
- 编写测试函数:测试函数的名称必须以Test开头,而且继承一个范例为*testing.T的参数。
- 利用t.Errorf或t.Fatalf来陈诉错误:假如测试未通过,可以利用这些方法来记载错误信息。
以下是一个简单的单元测试示例:- package main
- import "testing"
- // add 是被测试的函数
- func add(a, b int) int {
- return a + b
- }
- // TestAdd 是 add 函数的单元测试
- func TestAdd(t *testing.T) {
- result := add(1, 2)
- if result != 3 {
- t.Errorf("add(1, 2) = %d; want 3", result)
- }
- }
复制代码 要运行测试,可以在下令行中利用go test下令。
基准测试(Benchmark)
什么是基准测试
基准测试(Benchmark Testing),也称为性能测试,是一种丈量和评估软件或硬件性能的测试方法。在软件开发中,基准测试通常用于评估代码片断或算法的运行服从,包罗实验速率、内存利用、吞吐量等性能指标。
基准测试的重要目标是:
- 评估性能:确定代码或体系在特定条件下的性能表现。
- 性能优化:通过比力差别实现或设置的性能,资助开发者举行优化。
- 性能监控
:监控 软件或体系性能随时间的厘革,及时发现埋伏的性能题目。
基准测试的步调
基准测试用于衡量代码的性能,特别是实验速率。以下是编写基准测试的根本步调:
- 导入testing包。
- 编写基准测试函数:基准测试函数的名称必须以Benchmark开头,而且继承一个范例为*testing.B的参数。
- 利用b.N来重复实验测试代码:b.N是基准测试框架提供的,表现测试应该实验的次数。
以下是一个基准测试的示例:- package main
- import "testing"
- func BenchmarkAdd(b *testing.B) {
- for i := 0; i < b.N; i++ {
- add(1, 2)
- }
- }
复制代码 要运行基准测试,可以在下令行中利用go test -bench=.下令。
子测试和子基准测试
Go 1.7+ 引入了子测试和子基准测试的概念,允许在同一个测试函数中运行多个测试或基准测试。- func TestAdd(t *testing.T) {
- tests := []struct {
- a, b, want int
- }{
- {1, 2, 3},
- {2, 3, 5},
- {-1, -1, -2},
- }
- for _, tt := range tests {
- t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
- if got := add(tt.a, tt.b); got != tt.want {
- t.Errorf("add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
- }
- })
- }
- }
复制代码 覆盖率
Go还提供了代码覆盖率工具,用于衡量测试实验了多少代码。可以利用go test -cover来获取覆盖率。
计时方法
基准测试通常关注代码实验的时间。以下是几种常见的计时方法:
- Wall-time 计时:丈量实际颠末的时间,即从测试开始到竣事的总时间。
- CPU-time 计时:丈量处理处罚器实验测试代码所耗费的时间,不包罗等候I/O操纵或其他体系活动的时间。
- 用户-time 和体系-time:用户-time 是指步调在用户模式下实验所耗费的时间,体系-time 是指步调在内核模式下实验所耗费的时间。
我们同样可以通过ResetTimer计时器的方法来举行计时。
假设我们有一个简单的函数calculate,它实验一些盘算操纵:- package main
- import (
- "testing"
- "time"
- )
- // calculate 是一个简单的计算函数,用于基准测试
- func calculate(n int) int {
- sum := 0
- for i := 0; i < n; i++ {
- sum += i
- }
- return sum
- }
- // BenchmarkCalculate 是 calculate 函数的基准测试
- func BenchmarkCalculate(b *testing.B) {
- // 重置计时器
- b.ResetTimer()
- // 运行基准测试
- for i := 0; i < b.N; i++ {
- calculate(1000)
- }
- // 停止计时器
- b.StopTimer()
- // 报告内存分配情况
- b.ReportAllocs()
- }
- // 测试命令: go test -bench=.
复制代码 在这个基准测试中,我们利用了以下计时方法:
- b.ResetTimer():在开始实验基准测试之前重置计时器。
- b.StopTimer():在完成基准测试后制止计时器。
这两个方法确保我们只丈量calculate函数实验的时间,而不包罗设置测试环境所需的时间。
现在,让我们运行基准测试并查察结果:- go test -bench=Calculate -benchmem
复制代码 输出大概类似于以下内容:- goos: darwin
- goarch: amd64
- pkg: example
- cpu: Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
- BenchmarkCalculate-4 1000000 1060 ns/op 0 B/op 0 allocs/op
- PASS
- ok example 1.509s
复制代码 在这个输出中:
- BenchmarkCalculate-4 表现基准测试的名称和利用的CPU核心数。
- 1000000 是基准测试中实验的迭代次数(b.N)。
- 1060 ns/op 表现每次操纵的均匀时间(纳秒)。
- 0 B/op 表现每次操纵的均匀内存分配量(字节)。
- 0 allocs/op 表现每次操纵的均匀内存分配次数。
这个示例展示了怎样在Go中举行根本的计时和内存统计。通过-benchmem标记,我们可以得到内存分配的详细信息。
内存统计
内存统计是基准测试中另一个告急的方面,它资助开发者相识代码实验过程中的内存利用环境。以下是内存统计的一些关键点:
- 内存分配次数:代码实验过程中发生的内存分配次数。
- 内存分配量:代码实验过程中统共分配的内存量。
- 内存利用峰值:代码实验过程中内存利用的最高点。
在Go语言中,可以利用 testing 包提供的 BenchmarkResult 布局来获取内存统计信息,如下所示:- func BenchmarkFib(b *testing.B) {
- // ... 测试代码 ...
- result := testing.Benchmark(b.run)
- b.ReportAllocs() // 报告内存分配情况
- // 可以通过 result.AllocedBytesPerOp 等字段获取内存统计信息
- }
复制代码 并发基准测试
并发基准测试用于评估代码在多线程或多历程环境下的性能。以下是并发基准测试的一些关键点:
- 并发的级别:测试中同时运行的goroutine数量。
- 同步机制:在并发测试中,须要思量同步机制(如锁、通道等)对性能的影响。
- 竞争条件:并发测试可以显现埋伏的竞争条件或死锁题目。
在Go语言中,可以利用 runtime 包来控制并发基准测试的并发级别,如下所示:- func BenchmarkConcurrentFib(b *testing.B) {
- // 设置并发级别
- numGoroutines := runtime.NumCPU()
- b.SetParallelism(numGoroutines)
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- fib(10) // 并发执行 fib(10)
- }
- })
- }
复制代码 在这个例子中,SetParallelism 设置了基准测试的并发级别,而 RunParallel 则用于实验并发的基准测试。
总结
Go语言的测试框架简单而强盛,通过testing包,开发者可以轻松编写单元测试和基准测试来确保代码的精确性和性能。以下是一些最佳实践:
- 测试文件应该与被测试的代码放在同一包中。
- 测试函数的名称应该以Test或Benchmark开头。
- 利用子测试和子基准测试来构造干系的测试用例。
- 定期运行基准测试来监控
性能厘革。
- 利用覆盖率工具来确保测试覆盖了充足多的代码路径。
通过依照这些实践,可以确保Go项目标质量和性能。
|